From baf2758f284d020a51463cff05b9c065cd6bfba7 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 14 May 2026 20:21:11 -0500 Subject: [PATCH] some byte slice cleanup --- artnet.go | 2 +- dmx.go | 34 ++++++++++++++++++++++------------ dmx_test.go | 43 ++++++++++++++++++++++++++++++++++++++----- packet.go | 2 +- poll.go | 17 +++++++++++------ timecode.go | 23 +++++++++++++++++------ timecode_test.go | 40 ++++++++++++++++++++++++++++++++++++++-- 7 files changed, 128 insertions(+), 33 deletions(-) diff --git a/artnet.go b/artnet.go index 1e004c9..c5716f7 100644 --- a/artnet.go +++ b/artnet.go @@ -47,7 +47,7 @@ var ( OpDirectoryReply uint16 = 0x9b00 ) -var ArtNetID []uint8 = []uint8{'A', 'r', 't', '-', 'N', 'e', 't', 0x00} +var ArtNetID [8]uint8 = [8]uint8{'A', 'r', 't', '-', 'N', 'e', 't', 0x00} func Decode(bytes []byte) (ArtNetPacket, error) { if len(bytes) < 12 { diff --git a/dmx.go b/dmx.go index b6ca88d..06a79d9 100644 --- a/dmx.go +++ b/dmx.go @@ -7,7 +7,7 @@ import ( ) type ArtDmx struct { - ID []uint8 + ID [8]uint8 OpCode uint16 ProtVerHi uint8 ProtVerLo uint8 @@ -15,7 +15,6 @@ type ArtDmx struct { Physical uint8 SubUni uint8 Net uint8 - Length uint16 Data []uint8 } @@ -27,18 +26,22 @@ func (ad *ArtDmx) GetProtVer() uint16 { return uint16(ad.ProtVerHi)<<8 + uint16(ad.ProtVerLo) } -func (ad *ArtDmx) GetID() []uint8 { +func (ad *ArtDmx) GetID() [8]uint8 { return ad.ID } +func (ad *ArtDmx) Length() uint16 { + return uint16(len(ad.Data)) +} + func (ad *ArtDmx) UnmarshalBinary(data []byte) error { if len(data) < 18 { return errors.New("ArtDmx packet must be at least 18 bytes long") } - ad.ID = data[0:8] + copy(ad.ID[:], data[0:8]) - if !slices.Equal(ArtNetID, ad.ID) { + if !slices.Equal(ArtNetID[:], ad.ID[:]) { return errors.New("ID does not match Art-Net ID") } @@ -53,23 +56,30 @@ func (ad *ArtDmx) UnmarshalBinary(data []byte) error { ad.SubUni = data[offset+2] ad.Net = data[offset+3] - ad.Length = uint16(data[offset+4])<<8 + uint16(data[offset+5]) + length := int(data[offset+4])<<8 + int(data[offset+5]) dmxDataOffset := offset + 6 - if len(data[dmxDataOffset:]) < int(ad.Length) { + if len(data[dmxDataOffset:]) < length { return errors.New("ArtDmx packet length mismatch") } - ad.Data = make([]uint8, ad.Length) + ad.Data = data[dmxDataOffset : dmxDataOffset+length] - copy(ad.Data, data[dmxDataOffset:dmxDataOffset+int(ad.Length)]) return nil } func (ad *ArtDmx) MarshalBinary() ([]byte, error) { - data := []byte(ArtNetID) - data = append(data, byte(ad.OpCode), byte(ad.OpCode>>8), ad.ProtVerHi, ad.ProtVerLo, ad.Sequence, ad.Physical, ad.SubUni, ad.Net, byte(ad.Length>>8), byte(ad.Length)) - data = append(data, ad.Data...) + data := make([]byte, 8+10+ad.Length()) + copy(data[0:8], ad.ID[:]) + binary.LittleEndian.PutUint16(data[8:10], ad.OpCode) + data[10] = ad.ProtVerHi + data[11] = ad.ProtVerLo + data[12] = ad.Sequence + data[13] = ad.Physical + data[14] = ad.SubUni + data[15] = ad.Net + binary.BigEndian.PutUint16(data[16:18], ad.Length()) + copy(data[18:], ad.Data) return data, nil } diff --git a/dmx_test.go b/dmx_test.go index 16d5846..6046e60 100644 --- a/dmx_test.go +++ b/dmx_test.go @@ -15,7 +15,7 @@ func TestGoodArtDmx(t *testing.T) { { Data: []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Expected: &artnet.ArtDmx{ - ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, + ID: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, OpCode: artnet.OpDmx, ProtVerHi: 0, ProtVerLo: 14, @@ -23,7 +23,6 @@ func TestGoodArtDmx(t *testing.T) { Physical: 0, SubUni: 1, Net: 0, - Length: 512, Data: make([]uint8, 512), }, }, @@ -42,7 +41,7 @@ func TestGoodArtDmx(t *testing.T) { t.Fatalf("ArtDmx OpCode does not match got: %d expected: %d", got.OpCode, test.Expected.OpCode) } - if !slices.Equal(got.ID, test.Expected.ID) { + if !slices.Equal(got.ID[:], test.Expected.ID[:]) { t.Fatalf("ArtDmx ID does not match got: %+v expected: %+v", got.ID, test.Expected.ID) } @@ -70,8 +69,8 @@ func TestGoodArtDmx(t *testing.T) { t.Fatalf("ArtDmx Net does not match got: %d expected: %d", got.Net, test.Expected.Net) } - if got.Length != test.Expected.Length { - t.Fatalf("ArtDmx Length does not match got: %d expected: %d", got.Length, test.Expected.Length) + if got.Length() != test.Expected.Length() { + t.Fatalf("ArtDmx Length does not match got: %d expected: %d", got.Length(), test.Expected.Length()) } if !slices.Equal(got.Data, test.Expected.Data) { @@ -80,3 +79,37 @@ func TestGoodArtDmx(t *testing.T) { } } + +func BenchmarkArtDmxUnmarshalBinary(b *testing.B) { + data := []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 237, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + for b.Loop() { + got := artnet.ArtDmx{} + + err := got.UnmarshalBinary(data) + if err != nil { + b.Fatalf("failed to decode ArtDmx: %s", err) + } + } +} + +func BenchmarkArtDmxMarshalBinary(b *testing.B) { + data := artnet.ArtDmx{ + ID: [8]byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, + OpCode: artnet.OpDmx, + ProtVerHi: 0, + ProtVerLo: 14, + Sequence: 237, + Physical: 0, + SubUni: 1, + Net: 0, + Data: make([]uint8, 512), + } + + for b.Loop() { + _, err := data.MarshalBinary() + if err != nil { + b.Fatalf("failed to encode ArtDmx: %s", err) + } + } +} diff --git a/packet.go b/packet.go index f24f061..fbd0e2e 100644 --- a/packet.go +++ b/packet.go @@ -9,5 +9,5 @@ type ArtNetPacket interface { encoding.BinaryMarshaler GetOpCode() uint16 GetProtVer() uint16 - GetID() []uint8 + GetID() [8]uint8 } diff --git a/poll.go b/poll.go index 444293b..6254003 100644 --- a/poll.go +++ b/poll.go @@ -7,7 +7,7 @@ import ( ) type ArtPoll struct { - ID []uint8 + ID [8]uint8 OpCode uint16 ProtVerHi uint8 ProtVerLo uint8 @@ -31,7 +31,7 @@ func (ap *ArtPoll) GetProtVer() uint16 { return uint16(ap.ProtVerHi)<<8 + uint16(ap.ProtVerLo) } -func (ap *ArtPoll) GetID() []uint8 { +func (ap *ArtPoll) GetID() [8]uint8 { return ap.ID } @@ -41,9 +41,9 @@ func (ap *ArtPoll) UnmarshalBinary(data []byte) error { return errors.New("ArtPoll packet must be at least 14 bytes long") } - ap.ID = data[0:8] + copy(ap.ID[:], data[0:8]) - if !slices.Equal(ArtNetID, ap.ID) { + if !slices.Equal(ArtNetID[:], ap.ID[:]) { return errors.New("ID does not match Art-Net ID") } @@ -59,8 +59,13 @@ func (ap *ArtPoll) UnmarshalBinary(data []byte) error { } func (ap *ArtPoll) MarshalBinary() ([]byte, error) { - data := []byte(ArtNetID) - data = append(data, byte(ap.OpCode), byte(ap.OpCode>>8), ap.ProtVerHi, ap.ProtVerLo, ap.Flags, ap.DiagPriority) + data := make([]byte, 8+6) + copy(data[0:8], ap.ID[:]) + binary.LittleEndian.PutUint16(data[8:10], ap.OpCode) + data[10] = ap.ProtVerHi + data[11] = ap.ProtVerLo + data[12] = ap.Flags + data[13] = ap.DiagPriority //TODO(jwetzell): pack extended poll fields return data, nil } diff --git a/timecode.go b/timecode.go index c7d4c0b..3045f85 100644 --- a/timecode.go +++ b/timecode.go @@ -7,7 +7,7 @@ import ( ) type ArtTimeCode struct { - ID []uint8 + ID [8]uint8 OpCode uint16 ProtVerHi uint8 ProtVerLo uint8 @@ -28,7 +28,7 @@ func (atc *ArtTimeCode) GetProtVer() uint16 { return uint16(atc.ProtVerHi)<<8 + uint16(atc.ProtVerLo) } -func (atc *ArtTimeCode) GetID() []uint8 { +func (atc *ArtTimeCode) GetID() [8]uint8 { return atc.ID } @@ -37,9 +37,9 @@ func (atc *ArtTimeCode) UnmarshalBinary(data []byte) error { return errors.New("ArtTimeCode packet must be at least 14 bytes long") } - atc.ID = data[0:8] + copy(atc.ID[:], data[0:8]) - if !slices.Equal(ArtNetID, atc.ID) { + if !slices.Equal(ArtNetID[:], atc.ID[:]) { return errors.New("ID does not match Art-Net ID") } @@ -59,7 +59,18 @@ func (atc *ArtTimeCode) UnmarshalBinary(data []byte) error { } func (atc *ArtTimeCode) MarshalBinary() ([]byte, error) { - data := []byte(ArtNetID) - data = append(data, byte(atc.OpCode), byte(atc.OpCode>>8), atc.ProtVerHi, atc.ProtVerLo, atc.Filler1, atc.StreamId, atc.Frames, atc.Seconds, atc.Minutes, atc.Hours, atc.Type) + data := make([]byte, 8+11) + copy(data[0:8], atc.ID[:]) + binary.LittleEndian.PutUint16(data[8:10], atc.OpCode) + data[10] = atc.ProtVerHi + data[11] = atc.ProtVerLo + offset := 12 + data[offset] = atc.Filler1 + data[offset+1] = atc.StreamId + data[offset+2] = atc.Frames + data[offset+3] = atc.Seconds + data[offset+4] = atc.Minutes + data[offset+5] = atc.Hours + data[offset+6] = atc.Type return data, nil } diff --git a/timecode_test.go b/timecode_test.go index b634779..ed59da6 100644 --- a/timecode_test.go +++ b/timecode_test.go @@ -15,7 +15,7 @@ func TestGoodArtTimeCode(t *testing.T) { { Data: []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 151, 0, 14, 0, 0, 11, 17, 3, 0, 0}, Expected: &artnet.ArtTimeCode{ - ID: []byte{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, + ID: [8]uint8{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, OpCode: artnet.OpTimeCode, ProtVerHi: 0, ProtVerLo: 14, @@ -43,7 +43,7 @@ func TestGoodArtTimeCode(t *testing.T) { t.Fatalf("ArtTimeCode OpCode does not match got: %d expected: %d", got.OpCode, test.Expected.OpCode) } - if !slices.Equal(got.ID, test.Expected.ID) { + if !slices.Equal(got.ID[:], test.Expected.ID[:]) { t.Fatalf("ArtTimeCode ID does not match got: %+v expected: %+v", got.ID, test.Expected.ID) } @@ -85,3 +85,39 @@ func TestGoodArtTimeCode(t *testing.T) { } } + +func BenchmarkArtTimeCodeUnmarshalBinary(b *testing.B) { + data := []byte{65, 114, 116, 45, 78, 101, 116, 0, 0, 151, 0, 14, 0, 0, 11, 17, 3, 0, 0} + + for b.Loop() { + got := artnet.ArtTimeCode{} + + err := got.UnmarshalBinary(data) + if err != nil { + b.Fatalf("failed to decode ArtTimeCode: %s", err) + } + } +} + +func BenchmarkArtTimeCodeMarshalBinary(b *testing.B) { + data := artnet.ArtTimeCode{ + ID: [8]uint8{'A', 'r', 't', '-', 'N', 'e', 't', 0x00}, + OpCode: artnet.OpTimeCode, + ProtVerHi: 0, + ProtVerLo: 14, + Filler1: 0, + StreamId: 0, + Frames: 11, + Seconds: 17, + Minutes: 3, + Hours: 0, + Type: 0, + } + + for b.Loop() { + _, err := data.MarshalBinary() + if err != nil { + b.Fatalf("failed to encode ArtTimeCode: %s", err) + } + } +}