]> git.lizzy.rs Git - mt.git/blob - inv.go
Add inv (de)serialization
[mt.git] / inv.go
1 package mt
2
3 import (
4         "fmt"
5         "io"
6         "reflect"
7 )
8
9 type sentinal struct {
10         err error
11 }
12
13 func (s *sentinal) ret(err error) {
14         s.err = err
15         panic(s)
16 }
17
18 type Inv []NamedInvList
19
20 type NamedInvList struct {
21         Name string
22         InvList
23 }
24
25 func (inv Inv) List(name string) *NamedInvList {
26         for i, l := range inv {
27                 if l.Name == name {
28                         return &inv[i]
29                 }
30         }
31         return nil
32 }
33
34 func (i Inv) Serialize(w io.Writer) error {
35         for _, l := range i {
36                 if _, err := fmt.Fprintln(w, "List", l.Name, len(l.Stacks)); err != nil {
37                         return err
38                 }
39                 if err := l.Serialize(w); err != nil {
40                         return err
41                 }
42         }
43         _, err := fmt.Fprintln(w, "EndInventory")
44         return err
45 }
46
47 func (i *Inv) Deserialize(r io.Reader) (err error) {
48         s := new(sentinal)
49         defer func() {
50                 r := recover()
51                 if r, ok := r.(sentinal); ok {
52                         err = r.err
53                 }
54         }()
55
56         old := *i
57         *i = nil
58
59         for {
60                 if err := readCmdLn(r, map[string]interface{}{
61                         "List": func(name string, size int) {
62                                 l := old.List(name)
63                                 if l == nil {
64                                         l = &NamedInvList{Name: name}
65                                 }
66
67                                 if err := l.Deserialize(r); err != nil {
68                                         s.ret(fmt.Errorf("List %s %d: %w", name, size, err))
69                                 }
70                                 if len(l.Stacks) != size {
71                                         s.ret(fmt.Errorf("List %s %d: contains %d stacks", name, size, len(l.Stacks)))
72                                 }
73
74                                 *i = append(*i, *l)
75                         },
76                         "KeepList": func(name string) {
77                                 l := old.List(name)
78                                 if l == nil {
79                                         s.ret(fmt.Errorf("KeepList %s: list does not exist", name))
80                                 }
81
82                                 *i = append(*i, *l)
83                         },
84                         "EndInventory": func() {
85                                 s.ret(nil)
86                         },
87                 }); err != nil {
88                         if err == io.EOF {
89                                 s.ret(io.ErrUnexpectedEOF)
90                         }
91                         s.ret(err)
92                 }
93         }
94 }
95
96 type InvList struct {
97         Width  int
98         Stacks []Stack
99 }
100
101 func (l InvList) Serialize(w io.Writer) error {
102         if _, err := fmt.Fprintln(w, "Width", l.Width); err != nil {
103                 return err
104         }
105         for _, i := range l.Stacks {
106                 if i.Count > 0 {
107                         if _, err := fmt.Fprintln(w, "Item", i); err != nil {
108                                 return err
109                         }
110                 } else {
111                         if _, err := fmt.Fprintln(w, "Empty"); err != nil {
112                                 return err
113                         }
114                 }
115         }
116         _, err := fmt.Fprintln(w, "EndInventoryList")
117         return err
118 }
119
120 func (i *InvList) Deserialize(r io.Reader) (err error) {
121         s := new(sentinal)
122         defer func() {
123                 r := recover()
124                 if r, ok := r.(sentinal); ok {
125                         err = r.err
126                 }
127         }()
128
129         if _, err := fmt.Fscanf(r, "Width %d\n", &i.Width); err != nil {
130                 s.ret(err)
131         }
132
133         i.Stacks = i.Stacks[:0]
134
135         for {
136                 if err := readCmdLn(r, map[string]interface{}{
137                         "Empty": func() {
138                                 i.Stacks = append(i.Stacks, Stack{})
139                         },
140                         "Item": func(stk Stack) {
141                                 i.Stacks = append(i.Stacks, stk)
142                         },
143                         "Keep": func() {
144                                 if len(i.Stacks) < cap(i.Stacks) {
145                                         i.Stacks = i.Stacks[:len(i.Stacks)+1]
146                                 } else {
147                                         i.Stacks = append(i.Stacks, Stack{})
148                                 }
149                         },
150                         "EndInventoryList": func() {
151                                 s.ret(nil)
152                         },
153                 }); err != nil {
154                         if err == io.EOF {
155                                 s.ret(io.ErrUnexpectedEOF)
156                         }
157                         s.ret(err)
158                 }
159         }
160 }
161
162 func readCmdLn(r io.Reader, cmds map[string]interface{}) error {
163         if _, ok := r.(io.RuneScanner); !ok {
164                 r = &readRune{Reader: r, peekRune: -1}
165         }
166
167         var cmd string
168         if _, err := fmt.Fscan(r, &cmd); err != nil {
169                 return err
170         }
171
172         f, ok := cmds[cmd]
173         if !ok {
174                 return fmt.Errorf("unsupported line type: %+q", cmd)
175         }
176
177         t := reflect.TypeOf(f)
178
179         a := make([]interface{}, t.NumIn())
180         for i := range a {
181                 a[i] = reflect.New(t.In(i)).Interface()
182         }
183         fmt.Fscanln(r, a...)
184
185         args := make([]reflect.Value, t.NumIn())
186         for i := range args {
187                 args[i] = reflect.ValueOf(a[i]).Elem()
188         }
189         reflect.ValueOf(f).Call(args)
190
191         return nil
192 }