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// AllPriorities returns all valid priority values from lowest to highest.
 59func AllPriorities() []Priority {
 60	return []Priority{
 61		PriorityLowest,
 62		PriorityLow,
 63		PriorityNormal,
 64		PriorityHigh,
 65		PriorityHighest,
 66	}
 67}
 68
 69// ParsePriority parses a string to a Priority value (case-insensitive).
 70// Valid values: "lowest", "low", "normal", "high", "highest".
 71func ParsePriority(str string) (Priority, error) {
 72	switch strings.ToLower(str) {
 73	case "lowest":
 74		return PriorityLowest, nil
 75	case "low":
 76		return PriorityLow, nil
 77	case "normal":
 78		return PriorityNormal, nil
 79	case "high":
 80		return PriorityHigh, nil
 81	case "highest":
 82		return PriorityHighest, nil
 83	default:
 84		return 0, fmt.Errorf("%w: %q", ErrInvalidPriority, str)
 85	}
 86}
 87
 88// MarshalJSON implements [json.Marshaler].
 89// Priority marshals as its integer value.
 90func (p *Priority) MarshalJSON() ([]byte, error) {
 91	data, err := json.Marshal(int(*p))
 92	if err != nil {
 93		return nil, fmt.Errorf("marshaling priority: %w", err)
 94	}
 95
 96	return data, nil
 97}
 98
 99// UnmarshalJSON implements [json.Unmarshaler].
100// Priority unmarshals from an integer value in the range [-2, 2].
101func (p *Priority) UnmarshalJSON(data []byte) error {
102	if string(data) == "null" {
103		*p = PriorityNormal
104
105		return nil
106	}
107
108	var val int
109	if err := json.Unmarshal(data, &val); err != nil {
110		return fmt.Errorf("priority must be an integer: %w", err)
111	}
112
113	if val < -2 || val > 2 {
114		return fmt.Errorf("%w: %d", ErrPriorityOutOfRange, val)
115	}
116
117	*p = Priority(val)
118
119	return nil
120}