go-hep.org/x/hep@v0.38.1/sio/sio.go (about) 1 // Copyright ©2017 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sio 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io" 12 "math" 13 "reflect" 14 ) 15 16 // Reader is the interface that wraps the basic io.Reader interface 17 // and adds SIO pointer tagging capabilities. 18 type Reader interface { 19 io.Reader 20 21 Versioner 22 Tag(ptr any) error 23 Pointer(ptr any) error 24 } 25 26 // Writer is the interface that wraps the basic io.Writer interface 27 // and adds SIO pointer tagging capabilities. 28 type Writer interface { 29 io.Writer 30 31 Versioner 32 Tag(ptr any) error 33 Pointer(ptr any) error 34 } 35 36 // Marshaler is the interface implemented by an object that can marshal 37 // itself into a binary, sio-compatible, form. 38 type Marshaler interface { 39 MarshalSio(w Writer) error 40 } 41 42 // Unmarshaler is the interface implemented by an object that can 43 // unmarshal a binary, sio-compatible, representation of itself. 44 type Unmarshaler interface { 45 UnmarshalSio(r Reader) error 46 } 47 48 // Code is the interface implemented by an object that can 49 // unmarshal and marshal itself from and to a binary, sio-compatible, form. 50 type Codec interface { 51 Marshaler 52 Unmarshaler 53 } 54 55 // Linker is the interface implemented by an object that 56 // needs to recompute (internal) pointers, after the sio layer 57 // had performed pointer tagging/chasing relocation. 58 type Linker interface { 59 LinkSio(v uint32) error 60 } 61 62 // Versioner is the interface implemented by an object that 63 // tells which version of SIO serialization/deserialization it supports. 64 type Versioner interface { 65 VersionSio() uint32 66 } 67 68 type reader struct { 69 buf *bytes.Buffer 70 ver uint32 71 ptr map[any]uint32 72 tag map[any]uint32 73 } 74 75 func newReader(data []byte) *reader { 76 return &reader{ 77 buf: bytes.NewBuffer(data), 78 ptr: make(map[any]uint32), 79 tag: make(map[any]uint32), 80 } 81 } 82 83 func (r *reader) Read(data []byte) (int, error) { 84 return r.buf.Read(data) 85 } 86 87 func (r *reader) Bytes() []byte { 88 return r.buf.Bytes() 89 } 90 91 func (r *reader) Len() int { 92 return r.buf.Len() 93 } 94 95 func (r *reader) Next(n int) []byte { 96 return r.buf.Next(n) 97 } 98 99 func (r *reader) VersionSio() uint32 { 100 min := r.ver & uint32(0x0000ffff) 101 maj := (r.ver & uint32(0xffff0000)) >> 16 102 return maj*1000 + min 103 } 104 105 func (r *reader) Tag(ptr any) error { 106 var pid uint32 107 err := binary.Read(r.buf, binary.BigEndian, &pid) 108 if err != nil { 109 return err 110 } 111 if pid == ptagMarker { 112 return nil 113 } 114 r.tag[ptr] = pid 115 return nil 116 } 117 118 func (r *reader) Pointer(ptr any) error { 119 rptr := reflect.ValueOf(ptr) 120 if !(rptr.Kind() == reflect.Ptr && (rptr.Elem().Kind() == reflect.Ptr || rptr.Elem().Kind() == reflect.Interface)) { 121 panic(fmt.Errorf("sio: Reader.Pointer expects a pointer to pointer")) 122 } 123 124 var pid uint32 125 err := binary.Read(r, binary.BigEndian, &pid) 126 if err != nil { 127 return err 128 } 129 if pid == pntrMarker { 130 return nil 131 } 132 133 r.ptr[ptr] = pid 134 return nil 135 } 136 137 func (r *reader) relocate() { 138 ptrloop: 139 for ptr, pid := range r.ptr { 140 rptr := reflect.ValueOf(ptr) 141 for tag, tid := range r.tag { 142 if tid == pid { 143 rtag := reflect.ValueOf(tag) 144 rptr.Elem().Set(rtag) 145 continue ptrloop 146 } 147 } 148 } 149 } 150 151 type writer struct { 152 buf *bytes.Buffer 153 ver uint32 154 ids uint32 155 ptr map[uint32]any 156 tag map[any]uint32 157 } 158 159 func newWriter() *writer { 160 return &writer{ 161 buf: new(bytes.Buffer), 162 ptr: make(map[uint32]any), 163 tag: make(map[any]uint32), 164 } 165 } 166 167 func newWriterFrom(w *writer) *writer { 168 return &writer{ 169 buf: new(bytes.Buffer), 170 ver: w.ver, 171 ids: w.ids, 172 ptr: w.ptr, 173 tag: w.tag, 174 } 175 } 176 177 func (w *writer) Write(data []byte) (int, error) { 178 return w.buf.Write(data) 179 } 180 181 func (w *writer) Bytes() []byte { 182 return w.buf.Bytes() 183 } 184 185 func (w *writer) Len() int { 186 return w.buf.Len() 187 } 188 189 func (w *writer) VersionSio() uint32 { 190 min := w.ver & uint32(0x0000ffff) 191 maj := (w.ver & uint32(0xffff0000)) >> 16 192 return maj*1000 + min 193 } 194 195 func (w *writer) Tag(ptr any) error { 196 var id uint32 = ptagMarker 197 if _, ok := w.tag[ptr]; !ok { 198 err := w.genID() 199 if err != nil { 200 return err 201 } 202 w.tag[ptr] = w.ids 203 } 204 id = w.tag[ptr] 205 err := binary.Write(w.buf, binary.BigEndian, &id) 206 if err != nil { 207 return err 208 } 209 return nil 210 } 211 212 func (w *writer) Pointer(ptr any) error { 213 ptr = reflect.ValueOf(ptr).Elem().Interface() 214 var id uint32 = pntrMarker 215 if _, ok := w.tag[ptr]; !ok { 216 err := w.genID() 217 if err != nil { 218 return err 219 } 220 w.tag[ptr] = w.ids 221 } 222 id = w.tag[ptr] 223 err := binary.Write(w.buf, binary.BigEndian, &id) 224 if err != nil { 225 return err 226 } 227 return nil 228 } 229 230 func (w *writer) genID() error { 231 if w.ids+1 == math.MaxUint32 { 232 return errPointerIDOverflow 233 } 234 w.ids++ 235 return nil 236 } 237 238 var _ Reader = (*reader)(nil) 239 var _ Writer = (*writer)(nil)