diff options
Diffstat (limited to '')
-rw-r--r-- | pkg/types/binary.go | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/pkg/types/binary.go b/pkg/types/binary.go new file mode 100644 index 0000000..00a5417 --- /dev/null +++ b/pkg/types/binary.go @@ -0,0 +1,137 @@ +package types + +import ( + "bytes" + "database/sql" + "database/sql/driver" + "encoding" + "encoding/hex" + "encoding/json" + "github.com/icinga/icingadb/internal" + "github.com/icinga/icingadb/pkg/contracts" + "github.com/pkg/errors" +) + +// Binary nullable byte string. Hex as JSON. +type Binary []byte + +// nullBinary for validating whether a Binary is valid. +var nullBinary Binary + +// Equal returns whether the binaries are the same length and +// contain the same bytes. +func (binary Binary) Equal(equaler contracts.Equaler) bool { + b, ok := equaler.(Binary) + if !ok { + panic("bad Binary type assertion") + } + + return bytes.Equal(binary, b) +} + +// Valid returns whether the Binary is valid. +func (binary Binary) Valid() bool { + return !bytes.Equal(binary, nullBinary) +} + +// String returns the hex string representation form of the Binary. +func (binary Binary) String() string { + return hex.EncodeToString(binary) +} + +// MarshalText implements a custom marhsal function to encode +// the Binary as hex. MarshalText implements the +// encoding.TextMarshaler interface. +func (binary Binary) MarshalText() ([]byte, error) { + return []byte(binary.String()), nil +} + +// UnmarshalText implements a custom unmarshal function to decode +// hex into a Binary. UnmarshalText implements the +// encoding.TextUnmarshaler interface. +func (binary *Binary) UnmarshalText(text []byte) error { + b := make([]byte, hex.DecodedLen(len(text))) + _, err := hex.Decode(b, text) + if err != nil { + return internal.CantDecodeHex(err, string(text)) + } + *binary = b + + return nil +} + +// MarshalJSON implements a custom marshal function to encode the Binary +// as a hex string. MarshalJSON implements the json.Marshaler interface. +// Supports JSON null. +func (binary Binary) MarshalJSON() ([]byte, error) { + if !binary.Valid() { + return nil, nil + } + + return internal.MarshalJSON(binary.String()) +} + +// UnmarshalJSON implements a custom unmarshal function to decode +// a JSON hex string into a Binary. UnmarshalJSON implements the +// json.Unmarshaler interface. Supports JSON null. +func (binary *Binary) UnmarshalJSON(data []byte) error { + if string(data) == "null" || len(data) == 0 { + return nil + } + + var s string + if err := internal.UnmarshalJSON(data, &s); err != nil { + return err + } + b, err := hex.DecodeString(s) + if err != nil { + return internal.CantDecodeHex(err, s) + } + *binary = b + + return nil +} + +// Scan implements the sql.Scanner interface. +// Supports SQL NULL. +func (binary *Binary) Scan(src interface{}) error { + switch src := src.(type) { + case nil: + return nil + + case []byte: + if len(src) == 0 { + return nil + } + + b := make([]byte, len(src)) + copy(b, src) + *binary = b + + default: + return errors.Errorf("unable to scan type %T into Binary", src) + } + + return nil +} + +// Value implements the driver.Valuer interface. +// Supports SQL NULL. +func (binary Binary) Value() (driver.Value, error) { + if !binary.Valid() { + return nil, nil + } + + return []byte(binary), nil +} + +// Assert interface compliance. +var ( + _ contracts.ID = (*Binary)(nil) + _ encoding.TextMarshaler = (*Binary)(nil) + _ encoding.TextUnmarshaler = (*Binary)(nil) + _ json.Marshaler = (*Binary)(nil) + _ json.Unmarshaler = (*Binary)(nil) + _ sql.Scanner = (*Binary)(nil) + _ driver.Valuer = (*Binary)(nil) +) |