MarshalBinary time.Time: прогнозирование его размера в байтах - PullRequest
0 голосов
/ 04 марта 2020

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)
}

1 Ответ

1 голос
/ 04 марта 2020

Насколько я знаю, размер вывода MarshalBinary не подпадает под обещание Go 1 о совместимости :

Неуказанное поведение. Спецификация Go пытается явно указывать большинство свойств языка, но есть некоторые аспекты, которые не определены. Программы, зависящие от такого неуказанного поведения, в будущих выпусках могут прерваться.

Time.MarshalBinary не указывает размер выходных данных, поэтому его можно считать "неопределенным поведением" .

...