clone

an offline map explorer where each world, from a game map to a city's open data, ships as one .atlas file

feat/atlas-next-horizon
atlas / format / vnext / id.go
id.go 2.0K
1// Package vnext implements the schema-evolved Atlas container beside the2// frozen version 3 format. Its compatibility boundary is field identity and3// wire kind, not a document-wide schema version.4package vnext56import (7 "crypto/sha256"8 "encoding/hex"9 "encoding/json"10 "fmt"11 "strings"12)1314// ID is the globally unique identity of a type or field. Blocks use compact15// local directory positions after naming each field once with this full ID.16type ID [16]byte1718// IDFromName deterministically allocates an ID inside a namespace. Publishers19// can use a domain they control as the namespace without a central registry.20func IDFromName(namespace, name string) ID {21 digest := sha256.Sum256([]byte(namespace + "\x00" + name))22 var id ID23 copy(id[:], digest[:len(id)])24 // Mark the value as a name-derived UUID and set the RFC 4122 variant.25 id[6] = id[6]&0x0f | 0x5026 id[8] = id[8]&0x3f | 0x8027 return id28}2930// CoreID returns an identity in Atlas's own schema namespace.31func CoreID(name string) ID { return IDFromName("dev.atlas.core", name) }3233// ParseID accepts the customary dashed form or 32 hexadecimal digits.34func ParseID(value string) (ID, error) {35 var id ID36 plain := strings.ReplaceAll(value, "-", "")37 if len(plain) != hex.EncodedLen(len(id)) {38 return id, fmt.Errorf("ID %q is not 128 bits", value)39 }40 if _, err := hex.Decode(id[:], []byte(plain)); err != nil {41 return ID{}, fmt.Errorf("decode ID %q: %w", value, err)42 }43 return id, nil44}4546func (id ID) String() string {47 plain := hex.EncodeToString(id[:])48 return plain[:8] + "-" + plain[8:12] + "-" + plain[12:16] + "-" + plain[16:20] + "-" + plain[20:]49}5051func (id ID) isZero() bool { return id == ID{} }5253func (id ID) MarshalJSON() ([]byte, error) { return json.Marshal(id.String()) }5455func (id *ID) UnmarshalJSON(data []byte) error {56 var value string57 if err := json.Unmarshal(data, &value); err != nil {58 return fmt.Errorf("decode ID string: %w", err)59 }60 parsed, err := ParseID(value)61 if err != nil {62 return err63 }64 *id = parsed65 return nil66}