case.mx raw
1 package cm
2
3 // CaseUnmarshaler returns an function that can unmarshal text into
4 // [variant] or [enum] case T.
5 //
6 // [enum]: https://component-model.bytecodealliance.org/design/wit.html#enums
7 // [variant]: https://component-model.bytecodealliance.org/design/wit.html#variants
8 func CaseUnmarshaler[T ~uint8 | ~uint16 | ~uint32](cases [][]byte) func(v *T, text []byte) error {
9 if len(cases) <= linearScanThreshold {
10 return func(v *T, text []byte) error {
11 if len(text) == 0 {
12 return &emptyTextError{}
13 }
14 s := []byte(text)
15 for i := 0; i < len(cases); i++ {
16 if cases[i] == s {
17 *v = T(i)
18 return nil
19 }
20 }
21 return &noMatchingCaseError{}
22 }
23 }
24
25 m := map[string]T{}
26 for i, v := range cases {
27 m[v] = T(i)
28 }
29
30 return func(v *T, text []byte) error {
31 if len(text) == 0 {
32 return &emptyTextError{}
33 }
34 c, ok := m[[]byte(text)]
35 if !ok {
36 return &noMatchingCaseError{}
37 }
38 *v = c
39 return nil
40 }
41 }
42
43 const linearScanThreshold = 16
44
45 type emptyTextError struct{}
46
47 func (*emptyTextError) Error() string { return "empty text" }
48
49 type noMatchingCaseError struct{}
50
51 func (*noMatchingCaseError) Error() string { return "no matching case" }
52