Skip to content

Commit 15373b7

Browse files
Improve the function, complete the code, update the README content.
1 parent d50b167 commit 15373b7

File tree

8 files changed

+308
-87
lines changed

8 files changed

+308
-87
lines changed

README.md

Lines changed: 115 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,19 @@ func main() {
6767
- Composite types: strings, byte slices, arrays
6868
- Special types: padding bytes for alignment
6969

70-
### 2. Smart Field Tags
70+
### 2. Automatic Size Tracking
71+
72+
- Automatically manages lengths of variable-sized fields
73+
- Eliminates manual size calculation and tracking
74+
- Reduces potential errors in binary protocol implementations
75+
76+
### 3. Performance Optimizations
77+
78+
- Reflection caching for repeated operations
79+
- Efficient memory allocation
80+
- Optimized encoding/decoding paths
81+
82+
### 4. Smart Field Tags
7183

7284
```go
7385
type Example struct {
@@ -78,7 +90,7 @@ type Example struct {
7890
}
7991
```
8092

81-
### 3. Struct Tag Reference
93+
### 5. Struct Tag Reference
8294

8395
The `struc` tag supports various formats and options for precise binary data control:
8496

@@ -152,10 +164,12 @@ type ByteOrderTypes struct {
152164
type SpecialTypes struct {
153165
// Skip this field during packing/unpacking
154166
Ignored int `struc:"skip"`
167+
// Completely ignore this field (won't be included in binary)
168+
Private string `struc:"-"`
155169
// Size reference from another field
156170
Data []byte `struc:"sizefrom=Size"`
157171
// Custom type implementation
158-
Custom Custom
172+
YourCustomType CustomBinaryer
159173
}
160174
```
161175

@@ -165,42 +179,110 @@ Tag Format: `struc:"type,option1,option2"`
165179
- `big`/`little`: Byte order specification
166180
- `sizeof=Field`: Specify this field tracks another field's size
167181
- `sizefrom=Field`: Specify this field's size is tracked by another field
168-
- `skip`: Skip this field during packing/unpacking
182+
- `skip`: Skip this field during packing/unpacking (space is reserved in binary)
183+
- `-`: Completely ignore this field (not included in binary)
169184
- `[N]type`: Fixed-size array of type with length N
170185
- `[]type`: Dynamic-size array/slice of type
171186

172-
### 4. Automatic Size Tracking
187+
#### Why `omitempty` is not supported?
173188

174-
- Automatically manages lengths of variable-sized fields
175-
- Eliminates manual size calculation and tracking
176-
- Reduces potential errors in binary protocol implementations
189+
Unlike JSON serialization where fields can be optionally omitted, binary serialization requires a strict and fixed byte layout. Here's why `omitempty` is not supported:
177190

178-
### 5. Performance Optimizations
191+
1. **Fixed Binary Layout**
179192

180-
- Reflection caching for repeated operations
181-
- Efficient memory allocation
182-
- Optimized encoding/decoding paths
193+
- Binary protocols require precise byte positioning
194+
- Each field must occupy its predefined position and size
195+
- Omitting fields would break the byte alignment
196+
197+
2. **Parsing Dependencies**
198+
199+
- Binary data is parsed sequentially, byte by byte
200+
- If fields are omitted, the byte stream becomes misaligned
201+
- The receiving end cannot correctly reconstruct the data structure
202+
203+
3. **Protocol Stability**
204+
205+
- Binary protocols need strict version control
206+
- Allowing optional fields would break protocol stability
207+
- Makes it impossible to maintain backward compatibility
208+
209+
4. **Debugging Complexity**
210+
- With omitted fields, binary data becomes unpredictable
211+
- Makes it extremely difficult to debug byte streams
212+
- Increases the complexity of troubleshooting
213+
214+
If you need to mark certain fields as optional, consider these alternatives:
215+
216+
- Use explicit flag fields to indicate validity
217+
- Use default values for optional fields
218+
- Use the `struc:"-"` tag to completely exclude fields from serialization
183219

184220
## Advanced Usage
185221

186-
### Custom Endianness
222+
### Custom Type Implementation
223+
224+
If you need complete control over how a type is serialized and deserialized in binary format, you can implement the `CustomBinaryer` interface:
187225

188226
```go
189-
type Custom struct {
190-
BigEndian int32 `struc:"big"` // Explicit big-endian
191-
LittleEndian int32 `struc:"little"` // Explicit little-endian
227+
type CustomBinaryer interface {
228+
// Pack serializes data into a byte slice
229+
Pack(p []byte, opt *Options) (int, error)
230+
231+
// Unpack deserializes data from a Reader
232+
Unpack(r io.Reader, length int, opt *Options) error
233+
234+
// Size returns the size of serialized data
235+
Size(opt *Options) int
236+
237+
// String returns the string representation of the type
238+
String() string
192239
}
193240
```
194241

195-
### Fixed-Size Arrays
242+
For example, implementing a 3-byte integer type:
196243

197244
```go
198-
type FixedArray struct {
199-
Data [16]byte `struc:"[16]byte"` // Fixed-size byte array
200-
Ints [4]int32 `struc:"[4]int32"` // Fixed-size integer array
245+
// Usage example
246+
type Message struct {
247+
Value CustomBinaryer // Using custom type
248+
}
249+
250+
// Int3 is a custom 3-byte integer type
251+
type Int3 uint32
252+
253+
func (i *Int3) Pack(p []byte, opt *Options) (int, error) {
254+
// Convert 4-byte integer to 3 bytes
255+
var tmp [4]byte
256+
binary.BigEndian.PutUint32(tmp[:], uint32(*i))
257+
copy(p, tmp[1:]) // Only copy the last 3 bytes
258+
return 3, nil
259+
}
260+
261+
func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error {
262+
var tmp [4]byte
263+
if _, err := r.Read(tmp[1:]); err != nil {
264+
return err
265+
}
266+
*i = Int3(binary.BigEndian.Uint32(tmp[:]))
267+
return nil
268+
}
269+
270+
func (i *Int3) Size(opt *Options) int {
271+
return 3 // Fixed 3-byte size
272+
}
273+
274+
func (i *Int3) String() string {
275+
return strconv.FormatUint(uint64(*i), 10)
201276
}
202277
```
203278

279+
Benefits of custom types:
280+
281+
- Complete control over binary format
282+
- Support for special data layouts
283+
- Ability to implement compression or encryption
284+
- Suitable for handling legacy system formats
285+
204286
## Best Practices
205287

206288
1. **Use Appropriate Types**
@@ -297,19 +379,19 @@ goos: windows
297379
goarch: amd64
298380
pkg: github.com/shengyanli1982/struc/v2
299381
cpu: 12th Gen Intel(R) Core(TM) i5-12400F
300-
BenchmarkArrayEncode-12 3203236 373.2 ns/op 137 B/op 4 allocs/op
301-
BenchmarkSliceEncode-12 2985786 400.9 ns/op 137 B/op 4 allocs/op
302-
BenchmarkArrayDecode-12 3407203 349.8 ns/op 73 B/op 2 allocs/op
303-
BenchmarkSliceDecode-12 2768002 433.5 ns/op 112 B/op 4 allocs/op
304-
BenchmarkEncode-12 2656374 462.5 ns/op 168 B/op 4 allocs/op
305-
BenchmarkStdlibEncode-12 6035904 206.0 ns/op 136 B/op 3 allocs/op
306-
BenchmarkManualEncode-12 49696231 25.64 ns/op 64 B/op 1 allocs/op
307-
BenchmarkDecode-12 2812420 421.0 ns/op 103 B/op 2 allocs/op
308-
BenchmarkStdlibDecode-12 5953122 195.3 ns/op 80 B/op 3 allocs/op
309-
BenchmarkManualDecode-12 100000000 12.21 ns/op 8 B/op 1 allocs/op
310-
BenchmarkFullEncode-12 1000000 1800 ns/op 456 B/op 4 allocs/op
311-
BenchmarkFullDecode-12 598369 1974 ns/op 327 B/op 5 allocs/op
312-
BenchmarkFieldPool-12 19483657 62.86 ns/op 168 B/op 4 allocs/op
382+
BenchmarkArrayEncode-12 3215172 377.1 ns/op 137 B/op 4 allocs/op
383+
BenchmarkSliceEncode-12 3022616 395.9 ns/op 137 B/op 4 allocs/op
384+
BenchmarkArrayDecode-12 3407570 349.5 ns/op 73 B/op 2 allocs/op
385+
BenchmarkSliceDecode-12 2778577 424.7 ns/op 112 B/op 4 allocs/op
386+
BenchmarkEncode-12 2776862 431.2 ns/op 168 B/op 4 allocs/op
387+
BenchmarkStdlibEncode-12 5990055 197.5 ns/op 136 B/op 3 allocs/op
388+
BenchmarkManualEncode-12 59896976 24.82 ns/op 64 B/op 1 allocs/op
389+
BenchmarkDecode-12 2913640 404.5 ns/op 103 B/op 2 allocs/op
390+
BenchmarkStdlibDecode-12 5984299 195.2 ns/op 80 B/op 3 allocs/op
391+
BenchmarkManualDecode-12 100574584 11.95 ns/op 8 B/op 1 allocs/op
392+
BenchmarkFullEncode-12 1000000 1688 ns/op 456 B/op 4 allocs/op
393+
BenchmarkFullDecode-12 596047 1901 ns/op 327 B/op 5 allocs/op
394+
BenchmarkFieldPool-12 19045561 61.38 ns/op 168 B/op 4 allocs/op
313395
```
314396
315397
## License

0 commit comments

Comments
 (0)