package ident import ( "encoding/base64" "encoding/binary" "unsafe" ) // PartM represents the first half of [M]. type PartM struct { // A per-system value incremented by some unspecified amount every time the // metadata of a member first appears to the backend. Serial uint64 // An instant in time, some time after the corresponding member metadata // first appeared to the backend, represented in nanoseconds since // 1970-01-01. Time uint64 // Randomly generated value. The implementation must guarantee that the same // value cannot be emitted for a Time value. ID uint64 } // M represents a unique member identifier. type M struct { PartM // Underlying system. System S } func (*M) ident() {} const ( // SizeMember is the size of the binary representation of [M]. SizeMember = SizeSystem * 2 // EncodedSizeMember is the size of the string representation of [M]. EncodedSizeMember = SizeMember / 3 * 4 ) // EncodedSize returns the number of bytes appended by Encode. func (*M) EncodedSize() int { return EncodedSizeMember } // Encode appends the canonical string representation of pm to dst and returns // the extended buffer. func (pm *PartM) Encode(dst []byte) []byte { var buf [SizeMember - SizeSystem]byte p := buf[:] binary.LittleEndian.PutUint64(p, pm.Serial) p = p[8:] binary.LittleEndian.PutUint64(p, pm.Time) p = p[8:] binary.LittleEndian.PutUint64(p, pm.ID) return base64.URLEncoding.AppendEncode(dst, buf[:]) } // String returns the canonical string representation of pm. func (pm *PartM) String() string { s := pm.Encode(nil) return unsafe.String(unsafe.SliceData(s), len(s)) } // MarshalText returns the result of Encode. func (pm *PartM) MarshalText() (data []byte, err error) { return pm.Encode(nil), nil } // Encode appends the canonical string representation of mid to dst and returns // the extended buffer. func (mid *M) Encode(dst []byte) []byte { dst = mid.PartM.Encode(dst) return mid.System.Encode(dst) } // String returns the canonical string representation of mid. func (mid *M) String() string { s := mid.Encode(nil) return unsafe.String(unsafe.SliceData(s), len(s)) } // MarshalText returns the result of Encode. func (mid *M) MarshalText() (data []byte, err error) { return mid.Encode(nil), nil } // UnmarshalText strictly decodes data into pm. func (pm *PartM) UnmarshalText(data []byte) error { if len(data) != EncodedSizeMember-EncodedSizeSystem { return &UnexpectedSizeError{data, EncodedSizeMember - EncodedSizeSystem} } var buf [SizeMember - SizeSystem]byte if n, err := base64.URLEncoding.Decode( buf[:], data, ); err != nil { return err } else if n != SizeMember-SizeSystem { return ErrNewline } p := buf[:] pm.Serial = binary.LittleEndian.Uint64(p) p = p[8:] pm.Time = binary.LittleEndian.Uint64(p) p = p[8:] pm.ID = binary.LittleEndian.Uint64(p) return nil } // UnmarshalText strictly decodes data into mid. func (mid *M) UnmarshalText(data []byte) error { if len(data) != EncodedSizeMember { return &UnexpectedSizeError{data, EncodedSizeMember} } if err := mid.PartM.UnmarshalText( data[:EncodedSizeMember-EncodedSizeSystem], ); err != nil { return err } return mid.System.UnmarshalText(data[EncodedSizeMember-EncodedSizeSystem:]) }