-
Notifications
You must be signed in to change notification settings - Fork 0
/
stack.go
142 lines (121 loc) · 3.84 KB
/
stack.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package gallery
import (
"fmt"
"github.com/modernice/media-entity/image"
"github.com/modernice/media-entity/internal"
"github.com/modernice/media-entity/internal/slicex"
imgtools "github.com/modernice/media-tools/image"
)
// A Stack represents one or multiple variants of the same image. For example,
// an image may exist in multiple sizes.
type Stack[StackID, ImageID ID] struct {
ID StackID `json:"id"`
Variants []Image[ImageID] `json:"variants"`
Tags Tags `json:"tags"`
}
// Tags are the tags of a [Stack].
type Tags = imgtools.Tags
// NewTags returns a new [Tags] with the given tags. Duplicates are removed.
func NewTags(tags ...string) Tags {
return imgtools.NewTags(tags...)
}
// Image is an image of a [Stack]. An image may be the original image of the
// stack, or a variant of the original image. The ID of an Image is unique
// within a [Stack].
type Image[ImageID ID] struct {
image.Image
ID ImageID `json:"id"`
Original bool `json:"original"`
}
// Clone returns a deep-copy of the image.
func (img Image[ID]) Clone() Image[ID] {
img.Image = img.Image.Clone()
return img
}
// ZeroStack returns the zero-value [Stack].
func ZeroStack[StackID, ImageID ID]() (zero Stack[StackID, ImageID]) {
return zero
}
// Last returns the last [Image] of the [Stack].
func (s Stack[StackID, ImageID]) Last() Image[ImageID] {
if len(s.Variants) == 0 {
return zeroImage[ImageID]()
}
return s.Variants[len(s.Variants)-1]
}
// Clone returns a deep-copy of the Stack.
func (s Stack[StackID, ImageID]) Clone() Stack[StackID, ImageID] {
variants := make([]Image[ImageID], len(s.Variants))
for i, img := range s.Variants {
variants[i] = img.Clone()
}
s.Variants = variants
return s
}
// Original returns the original image of the stack, or the zero [Image] if the
// stack does not contain an original image.
func (s Stack[StackID, ImageID]) Original() Image[ImageID] {
for _, img := range s.Variants {
if img.Original {
return img
}
}
return zeroImage[ImageID]()
}
// ContainsOriginal returns whether the Stack contains an [Image] that has its
// Original field set to true.
func (s Stack[StackID, ImageID]) ContainsOriginal() bool {
for _, img := range s.Variants {
if img.Original {
return true
}
}
return false
}
// Clear returns a copy of the Stack will all variants removed except for the original.
func (s Stack[StackID, ImageID]) Clear() Stack[StackID, ImageID] {
s = s.Clone()
s.Variants = slicex.Filter(s.Variants, func(img Image[ImageID]) bool {
return img.Original
})
return s
}
// Image returns the [Image] with the given id, or false if the stack does not
// contain an [Image] with that id.
func (s Stack[StackID, ImageID]) Image(id ImageID) (Image[ImageID], bool) {
for _, img := range s.Variants {
if img.ID == id {
return img, true
}
}
return zeroImage[ImageID](), false
}
// Variant is an alias for s.Image.
func (s Stack[StackID, ImageID]) Variant(id ImageID) (Image[ImageID], bool) {
return s.Image(id)
}
// NewVariant returns a new gallery [Image] with the given id. No error is
// returned if the provided ImageID already exists in the [Stack].
func (s Stack[StackID, ImageID]) NewVariant(id ImageID, img image.Image) (Image[ImageID], error) {
if id == internal.Zero[ImageID]() {
return zeroImage[ImageID](), fmt.Errorf("image id: %w", ErrEmptyID)
}
return Image[ImageID]{
ID: id,
Image: img.Normalize(),
Original: false,
}, nil
}
// Tag returns a copy of the [Stack] with the given tags added.
func (s Stack[StackID, ImageID]) Tag(tags ...string) Stack[StackID, ImageID] {
s.Tags = s.Tags.With(tags...)
return s
}
// Tag returns a copy of the [Stack] with the given tags removed.
func (s Stack[StackID, ImageID]) Untag(tags ...string) Stack[StackID, ImageID] {
s.Tags = s.Tags.Without(tags...)
return s
}
func zeroImage[ImageID ID]() (zero Image[ImageID]) {
return zero
}