github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekatyp/ulid.go (about)

     1  // Copyright © 2021. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekatyp
     7  
     8  import (
     9  	"bytes"
    10  	"database/sql/driver"
    11  
    12  	"github.com/qioalice/ekago/v3/ekarand"
    13  
    14  	"github.com/oklog/ulid/v2"
    15  )
    16  
    17  type (
    18  	// ULID is a Universally Unique Lexicographically Sortable Identifier.
    19  	// It's a drop-in replacement of UUID.
    20  	// Read more: https://github.com/ulid/spec .
    21  	ULID ulid.ULID
    22  )
    23  
    24  // ---------------------------- UUID COMMON METHODS --------------------------- //
    25  // ---------------------------------------------------------------------------- //
    26  
    27  // Equal returns true if both of ULID s are equal, otherwise returns false.
    28  func (u ULID) Equal(anotherUlid ULID) bool {
    29  	return bytes.Equal(u[:], anotherUlid[:])
    30  }
    31  
    32  // IsNil reports whether current ULID is empty (nil).
    33  func (u ULID) IsNil() bool {
    34  	return u == ULID(_UUID_NULL)
    35  }
    36  
    37  // SetNil sets the current ULID to zero ULID. Returns modified ULID.
    38  func (u *ULID) SetNil() *ULID {
    39  	*u = ULID(_UUID_NULL)
    40  	return u
    41  }
    42  
    43  // Bytes returns bytes slice representation of ULID.
    44  func (u ULID) Bytes() []byte {
    45  	return u[:]
    46  }
    47  
    48  // String returns a lexicographically sortable string encoded ULID
    49  // (26 characters, non-standard base 32) e.g. 01AN4Z07BY79KA1307SR9X4MV3
    50  // Format: tttttttttteeeeeeeeeeeeeeee where t is time and e is entropy.
    51  func (u ULID) String() string {
    52  	return ulid.ULID(u).String()
    53  }
    54  
    55  // --------------------------- UUID CREATION HELPERS -------------------------- //
    56  // ---------------------------------------------------------------------------- //
    57  
    58  // ULID_OrPanic is a helper that wraps a call to a function returning (ULID, error)
    59  // and panics if the error is non-nil.
    60  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
    61  func ULID_OrPanic(u ULID, err error) ULID {
    62  	if err != nil {
    63  		panic(err)
    64  	}
    65  	return u
    66  }
    67  
    68  // ULID_OrNil is a helper that wraps a call to a function returning (ULID, error)
    69  // and returns zero ULID if the error is non-nil.
    70  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
    71  func ULID_OrNil(u ULID, err error) ULID {
    72  	if err != nil {
    73  		return ULID(_UUID_NULL)
    74  	}
    75  	return u
    76  }
    77  
    78  // ------------------------------ ULID GENERATORS ----------------------------- //
    79  // ---------------------------------------------------------------------------- //
    80  
    81  // ULID_New() returns an new ULID based on the current time and math/rand entropy.
    82  // Thread-safety.
    83  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
    84  func ULID_New() (ULID, error) {
    85  	u, err := ulid.New(ulid.Now(), (*ekarand.MathRandReader)(nil))
    86  	return ULID(u), err
    87  }
    88  
    89  // ------------------- ULID GENERATOR'S WRAPPERS OF HELPERS ------------------- //
    90  // ---------------------------------------------------------------------------- //
    91  
    92  // Next methods are the same as just generators but it panics
    93  // if any error occurred while ULID been generated.
    94  
    95  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
    96  func ULID_New_OrPanic() ULID {
    97  	return ULID_OrPanic(ULID_New())
    98  }
    99  
   100  // Next methods are the same as just generators but it returns
   101  // a zero ULID if any error is occurred while UUID been generated.
   102  
   103  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
   104  func ULID_New_OrNil() ULID {
   105  	return ULID_OrNil(ULID_New())
   106  }
   107  
   108  // Next methods are the same as just generators but it returns
   109  // only one argument - an error and saves generated ULID as output argument
   110  // by the address provided by 'dest' arg.
   111  //
   112  // It's useful when you awaits only one argument for being returned.
   113  // For example in if statement to omit else branch.
   114  //
   115  // WARNING!
   116  // No nil check! 'dest' must be not nil, panic otherwise.
   117  
   118  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
   119  func ULID_New_To(dest *ULID) (err error) {
   120  	*dest, err = ULID_New()
   121  	return
   122  }
   123  
   124  // ------------------------------- ULID PARSERS ------------------------------- //
   125  // ---------------------------------------------------------------------------- //
   126  
   127  // ULID_FromString returns ULID parsed from string input.
   128  // Input is expected in a form accepted by UnmarshalText.
   129  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
   130  func ULID_FromString(input string) (ULID, error) {
   131  	u, err := ulid.ParseStrict(input)
   132  	return ULID(u), err
   133  }
   134  
   135  // -------------------- ULID PARSER'S WRAPPERS OF HELPERS --------------------- //
   136  // ---------------------------------------------------------------------------- //
   137  
   138  // ULID_FromString_OrPanic is the same as ULID_OrPanic(ULID_FromString(input)).
   139  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
   140  func ULID_FromString_OrPanic(input string) ULID {
   141  	return ULID_OrPanic(ULID_FromString(input))
   142  }
   143  
   144  // ULID_FromString_OrNil is the same as ULID_OrNil(UUID_FromString(input)).
   145  // noinspection GoSnakeCaseUsage (Intellij IDEA suppress snake case warning).
   146  func ULID_FromString_OrNil(input string) ULID {
   147  	return ULID_OrNil(ULID_FromString(input))
   148  }
   149  
   150  // ------------------------ UUID TEXT ENCODER/DECODER ------------------------- //
   151  // ---------------------------------------------------------------------------- //
   152  
   153  // MarshalText implements the encoding.TextMarshaler interface by
   154  // returning the string encoded ULID.
   155  func (u ULID) MarshalText() ([]byte, error) {
   156  	return ulid.ULID(u).MarshalText()
   157  }
   158  
   159  // MarshalTextTo writes the ULID as a string to the given buffer.
   160  // ErrBufferSize is returned when the len(dst) != 26.
   161  func (u ULID) MarshalTextTo(dest []byte) error {
   162  	return ulid.ULID(u).MarshalTextTo(dest)
   163  }
   164  
   165  // UnmarshalText implements the encoding.TextUnmarshaler interface by
   166  // parsing the data as string encoded ULID.
   167  //
   168  // ErrDataSize is returned if the len(v) is different from an encoded
   169  // ULID's length. Invalid encodings produce undefined ULIDs.
   170  func (u *ULID) UnmarshalText(data []byte) error {
   171  	return (*ulid.ULID)(u).UnmarshalText(data)
   172  }
   173  
   174  // ------------------------ UUID JSON ENCODER/DECODER ------------------------- //
   175  // ---------------------------------------------------------------------------- //
   176  
   177  // MarshalJSON implements the encoding/json.Marshaler interface.
   178  // Returns a JSON string with encoded ULID with the followed format:
   179  // "01F58MK33HZR24YGEFXWV619XB". Returns JSON null if ULID is nil.
   180  func (u ULID) MarshalJSON() ([]byte, error) {
   181  
   182  	if u.IsNil() {
   183  		return _UUID_JSON_NULL, nil
   184  	}
   185  
   186  	buf := make([]byte, ulid.EncodedSize+2)
   187  	buf[0], buf[len(buf)-1] = '"', '"'
   188  
   189  	if err := ulid.ULID(u).MarshalTextTo(buf[1 : len(buf)-1]); err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	return buf, nil
   194  }
   195  
   196  // UnmarshalJSON implements the encoding/json.Unmarshaler interface.
   197  // Decodes data as encoded JSON ULID string and saves the result to u.
   198  // Supports JSON null values.
   199  func (u *ULID) UnmarshalJSON(data []byte) error {
   200  
   201  	if len(data) == 0 || bytes.Compare(data, _UUID_JSON_NULL) == 0 {
   202  		return nil
   203  	}
   204  
   205  	if len(data) != ulid.EncodedSize+2 {
   206  		return ulid.ErrDataSize
   207  	}
   208  
   209  	return (*ulid.ULID)(u).UnmarshalText(data[1 : len(data)-1])
   210  }
   211  
   212  // ----------------------- UUID BINARY ENCODER/DECODER ------------------------ //
   213  // ---------------------------------------------------------------------------- //
   214  
   215  // MarshalBinary implements the encoding.BinaryMarshaler interface by
   216  // returning the ULID as a byte slice.
   217  func (u ULID) MarshalBinary() ([]byte, error) {
   218  	return ulid.ULID(u).MarshalBinary()
   219  }
   220  
   221  // MarshalBinaryTo writes the binary encoding of the ULID to the given buffer.
   222  // ErrBufferSize is returned when the len(dst) != 16.
   223  func (u ULID) MarshalBinaryTo(dst []byte) error {
   224  	return ulid.ULID(u).MarshalBinaryTo(dst)
   225  }
   226  
   227  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface by
   228  // copying the passed data and converting it to an ULID. ErrDataSize is
   229  // returned if the data length is different from ULID length.
   230  func (u *ULID) UnmarshalBinary(data []byte) error {
   231  	return (*ulid.ULID)(u).UnmarshalBinary(data)
   232  }
   233  
   234  // ------------------------- UUID SQL ENCODER/DECODER ------------------------- //
   235  // ---------------------------------------------------------------------------- //
   236  
   237  // Value implements the sql/driver.Valuer interface. This returns the value
   238  // represented as a string.
   239  func (u ULID) Value() (driver.Value, error) {
   240  	return ulid.ULID(u).MarshalText()
   241  }
   242  
   243  // Scan implements the sql.Scanner interface. It supports scanning
   244  // a string or byte slice.
   245  func (u *ULID) Scan(src any) error {
   246  	return (*ulid.ULID)(u).Scan(src)
   247  }