priority.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package lunatask
  6
  7import (
  8	"encoding/json"
  9	"errors"
 10	"fmt"
 11	"strings"
 12)
 13
 14// Errors returned by Priority operations.
 15var (
 16	// ErrInvalidPriority is returned when parsing an unknown priority string.
 17	ErrInvalidPriority = errors.New("invalid priority")
 18	// ErrPriorityOutOfRange is returned when a priority value is outside [-2, 2].
 19	ErrPriorityOutOfRange = errors.New("priority out of range")
 20)
 21
 22// Priority represents task priority level from lowest (-2) to highest (2).
 23// The default priority is [PriorityNormal] (0).
 24type Priority int
 25
 26// Task priority levels. See [Priority] for the full range.
 27const (
 28	PriorityLowest  Priority = -2
 29	PriorityLow     Priority = -1
 30	PriorityNormal  Priority = 0
 31	PriorityHigh    Priority = 1
 32	PriorityHighest Priority = 2
 33)
 34
 35// String returns the lowercase name of the priority level.
 36func (p *Priority) String() string {
 37	switch *p {
 38	case PriorityLowest:
 39		return "lowest"
 40	case PriorityLow:
 41		return "low"
 42	case PriorityNormal:
 43		return "normal"
 44	case PriorityHigh:
 45		return "high"
 46	case PriorityHighest:
 47		return "highest"
 48	default:
 49		return fmt.Sprintf("Priority(%d)", *p)
 50	}
 51}
 52
 53// Valid reports whether the priority is within the valid range [-2, 2].
 54func (p *Priority) Valid() bool {
 55	return *p >= PriorityLowest && *p <= PriorityHighest
 56}
 57
 58// ParsePriority parses a string to a Priority value (case-insensitive).
 59// Valid values: "lowest", "low", "normal", "high", "highest".
 60func ParsePriority(str string) (Priority, error) {
 61	switch strings.ToLower(str) {
 62	case "lowest":
 63		return PriorityLowest, nil
 64	case "low":
 65		return PriorityLow, nil
 66	case "normal":
 67		return PriorityNormal, nil
 68	case "high":
 69		return PriorityHigh, nil
 70	case "highest":
 71		return PriorityHighest, nil
 72	default:
 73		return 0, fmt.Errorf("%w: %q", ErrInvalidPriority, str)
 74	}
 75}
 76
 77// MarshalJSON implements [json.Marshaler].
 78// Priority marshals as its integer value.
 79func (p *Priority) MarshalJSON() ([]byte, error) {
 80	data, err := json.Marshal(int(*p))
 81	if err != nil {
 82		return nil, fmt.Errorf("marshaling priority: %w", err)
 83	}
 84
 85	return data, nil
 86}
 87
 88// UnmarshalJSON implements [json.Unmarshaler].
 89// Priority unmarshals from an integer value in the range [-2, 2].
 90func (p *Priority) UnmarshalJSON(data []byte) error {
 91	if string(data) == "null" {
 92		*p = PriorityNormal
 93
 94		return nil
 95	}
 96
 97	var val int
 98	if err := json.Unmarshal(data, &val); err != nil {
 99		return fmt.Errorf("priority must be an integer: %w", err)
100	}
101
102	if val < -2 || val > 2 {
103		return fmt.Errorf("%w: %d", ErrPriorityOutOfRange, val)
104	}
105
106	*p = Priority(val)
107
108	return nil
109}