TL; DR;
Можно ли предсказать буфер, возвращаемый размером time.Time.MarshalBinary () - для помощи во время двоичного демаршалинга других пользовательских типов.
Попытка написать compact BinaryMarshaler для моего типа (т.е. избегать хранения ненужных маркеров размера):
type Item struct {
t time.Time
m *pb.Device // implements proto.Message - so use proto.Marshal(...) to Marshal
}
Оба поля имеют BinaryMarshaler, поэтому это должно быть легко. Первый проход, это было добавить оба маршалированных []bytes
вместе (время первое, прото. Сообщение второе). Но как Unmarshal
, так как time.Time.UnmarshalBinary не указывает, сколько байтов было использовано - так какое смещение следует использовать, чтобы начать proto.Message
unmarshaling?
Проверка источник времени предполагает, что time.Time.MarshalBinary()
всегда будет возвращать 15 байтов (первый байт содержит версию алгоритма 1
). Похоже, что это верно для go версий 1.2.2
до сегодняшнего дня (1.14
).
Так что можно вычислить количество байтов, потребляемых time.UnmarshalBinary
, чтобы помочь в пользовательских BinaryUnmarshalers
- и избегайте жестко заданных предположений, таких как:
func (i *Item) UnmarshalBinary(b []byte) error {
const (
timeV = 1
timeV1Len = 15
)
if len(b) == 0 {
*i = Item{} // no data - set to zero value
return nil
}
if b[0] != timeV {
return fmt.Errorf("time.Time binary marshaled at unsupported version %d (expected version %d)", b[0], timeV)
}
if len(b) < timeV1Len {
return fmt.Errorf("data too short: should be >= %d bytes, got %d byte(s)", timeV1Len, len(b))
}
if err = i.t.UnmarshalBinary(b[:timeV1Len]); err != nil {
return err
}
if len(b[timeV1Len:]) == 0 {
i.m = nil // no more data, so set Message nil
return nil
}
i.m = &pb.Device{}
return proto.Unmarshal(b[timeV1Len:], i.m)
}