hopp/message.go
2025-01-09 02:31:15 -05:00

59 lines
1.8 KiB
Go

package hopp
import "fmt"
import "encoding"
import "git.tebibyte.media/sashakoshka/hopp/tape"
// Message is any object that is both a binary marshaler and unmarshaler.
type Message interface {
Method() uint16
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
}
var _ Message = new(MessageData)
// MessageData can hold the structure of any message. It can be used to alter
// a protocol at runtime, transmit data with arbitrary keys, etc. Bear in mind
// that is less performant than generating code because it has to make extra
// memory allocations.
type MessageData struct {
Methd uint16
Pairs map[uint16] []byte
}
// Method returns the message's method field.
func (this *MessageData) Method() uint16 {
return this.Methd
}
// MarshalBinary implements the [encoding.BinaryMarshaler] interface.
func (this *MessageData) MarshalBinary() ([]byte, error) {
buffer, err := tape.EncodePairs(this.Pairs)
if err != nil { return nil, fmt.Errorf("marshaling MessageData: %w", err) }
return buffer, nil
}
// UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
func (this *MessageData) UnmarshalBinary(buffer []byte) error {
this.Pairs = make(map[uint16] []byte)
pairs, err := tape.DecodePairs(buffer)
if err != nil { return fmt.Errorf("unmarshaling MessageData: %w", err) }
for key, value := range pairs {
this.Pairs[key] = value
}
return nil
}
// Protocol maps methods to functions that create messages. The messages must be
// passed by reference, and the functions must return a new object every time.
type Protocol map[uint16] func() Message
// Add adds messages to the protocol. Messages with conflicting methods will
// be replaced.
func (this Protocol) Add(messages ...func() Message) {
for _, message := range messages {
this[message().Method()] = message
}
}