Documentation ¶
Overview ¶
Package id describes C4's dot-delimited IDs.
Index ¶
- Constants
- Variables
- func MapGlob(m interface{}, glob ID) (interface{}, error)
- func SearchSlice(haystack []ID, needle ID) int
- func Sort(ids []ID)
- type ID
- func (i ID) Equal(i2 ID) bool
- func (i ID) HasPrefix(prefix ID) bool
- func (i ID) HasSuffix(suffix ID) bool
- func (i ID) IsEmpty() bool
- func (i ID) Join(r ID) ID
- func (i ID) Less(i2 ID) bool
- func (i ID) MarshalText() ([]byte, error)
- func (i ID) Matches(glob ID) (bool, error)
- func (i *ID) Set(value string) error
- func (i ID) String() string
- func (i ID) Tags() []string
- func (i ID) Triple() (f, v string, s ID)
- func (i ID) Uncons() (hd string, tl ID, ok bool)
- func (i *ID) UnmarshalText(b []byte) error
- func (i ID) Unsnoc() (hd ID, tl string, ok bool)
Examples ¶
Constants ¶
const ( // ArchFamilyC is the tag representing the C pseudo-architecture family. ArchFamilyC = "c" // ArchFamilyX86 is the tag representing the X86 architecture family. ArchFamilyX86 = "x86" // ArchFamilyArm is the tag representing the 32-bit Arm architecture family. ArchFamilyArm = "arm" // ArchFamilyAArch64 is the tag representing the 64-bit Arm architecture family. ArchFamilyAArch64 = "aarch64" // ArchFamilyPPC is the tag representing the PowerPC architecture family. ArchFamilyPPC = "ppc" // ArchVariantArm7 is the tag representing the arm7(-a) Arm variant. ArchVariantArm7 = "7" // ArchVariantArm8 is the tag representing the arm8(-a) Arm variant. ArchVariantArm8 = "8" // ArchVariantArmCortexA72 is the tag representing the Cortex-A72 Arm variant. // This variant is, for example, that used on the Raspberry Pi 4. ArchVariantArmCortexA72 = "cortex-a72" // ArchVariantAArch648 is the tag representing the arm8.x(-a) AArch64 variant. ArchVariantAArch648 = "8" // ArchSubVariantAArch6481 is the tag representing the arm8.1(-a) AArch64 variant. ArchSubVariantAArch6481 = "1" // ArchVariantPPC64LE is the tag representing the 64-bit little-endian PPC variant. ArchVariantPPC64LE = "64le" // ArchSubVariantPPCPOWER7 is the tag representing the POWER7 PPC sub-variant. ArchSubVariantPPCPOWER7 = "power7" // ArchSubVariantPPCPOWER8 is the tag representing the POWER8 PPC sub-variant. ArchSubVariantPPCPOWER8 = "power8" // ArchSubVariantPPCPOWER9 is the tag representing the POWER9 PPC sub-variant. ArchSubVariantPPCPOWER9 = "power9" // ArchVariantX8664 is the tag representing the 64-bit x86 variant. ArchVariantX8664 = "64" // ArchSubVariantX86Broadwell is the tag representing the Intel Broadwell x86-64 subvariant. ArchSubVariantX86Broadwell = "broadwell" // ArchSubVariantX86Skylake is the tag representing the Intel Skylake x86-64 subvariant. // This variant is, for example, that used in 2016 MacBook Pros. ArchSubVariantX86Skylake = "skylake" )
const ( // SepTag is the identifier tag separator. // It is exported for testing and sanitisation purposes. SepTag = "." )
const TagGlob = "*"
TagGlob is the tag used in a glob expression to indicate that everything before it should be a prefix, and everything after a suffix, of the matched ID.
Variables ¶
var ( // ErrTagHasSep occurs when a tag passed to New contains the separator rune. ErrTagHasSep = errors.New("tag contains separator") // ErrTagEmpty occurs when a tag passed to New is empty. ErrTagEmpty = errors.New("tag empty") )
var ( // ArchC is the architecture ID for C. // (C isn't an architecture, but certain parts of the backend system are easier if we treat it as one.) ArchC = ID{/* contains filtered or unexported fields */} // ArchX86 is the architecture ID for x86 (generic, assumed 32-bit). ArchX86 = ID{/* contains filtered or unexported fields */} // ArchX8664 is the architecture ID for x86-64. ArchX8664 = ID{/* contains filtered or unexported fields */} // ArchX86Broadwell is the architecture ID for x86-64 Broadwell. ArchX86Broadwell = ID{/* contains filtered or unexported fields */} // ArchX86Skylake is the architecture ID for x86-64 Skylake. ArchX86Skylake = ID{/* contains filtered or unexported fields */} // ArchArm is the architecture ID for ARM (generic, 32-bit). ArchArm = ID{/* contains filtered or unexported fields */} // ArchArm7 is the architecture ID for arm7(-a). ArchArm7 = ID{/* contains filtered or unexported fields */} // ArchArm8 is the architecture ID for arm8(-a). ArchArm8 = ID{/* contains filtered or unexported fields */} // ArchArmCortexA72 is the architecture ID for arm Cortex-A72. ArchArmCortexA72 = ID{/* contains filtered or unexported fields */} // ArchAArch64 is the architecture ID for ARM (generic, 64-bit). ArchAArch64 = ID{/* contains filtered or unexported fields */} // ArchAArch648 is the architecture ID for ARM 64-bit version 8.x. ArchAArch648 = ID{/* contains filtered or unexported fields */} // ArchAArch6481 is the architecture ID for ARM 64-bit version 8.1. ArchAArch6481 = ID{/* contains filtered or unexported fields */} // ArchPPC is the architecture ID for PowerPC. ArchPPC = ID{/* contains filtered or unexported fields */} // ArchPPC64LE is the architecture ID for PowerPC64LE. ArchPPC64LE = ID{/* contains filtered or unexported fields */} // ArchPPCPOWER7 is the architecture ID for POWER7. ArchPPCPOWER7 = ID{/* contains filtered or unexported fields */} // ArchPPCPOWER8 is the architecture ID for POWER8. ArchPPCPOWER8 = ID{/* contains filtered or unexported fields */} // ArchPPCPOWER9 is the architecture ID for POWER9. ArchPPCPOWER9 = ID{/* contains filtered or unexported fields */} // CStyleGCC is the compiler style ID for GCC. CStyleGCC = ID{/* contains filtered or unexported fields */} )
var ErrBadGlob = errors.New("malformed glob expression")
ErrBadGlob occurs when Matches gets a malformed glob expression.
var ErrNotMap = errors.New("not a map with ID keys")
ErrNotMap occurs when we try to use an ID map function on something that isn't an ID map.
Functions ¶
func MapGlob ¶
MapGlob filters a string map m to those keys that match glob when interpreted as IDs.
Example ¶
ExampleMapGlob is a runnable example for MapGlob.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { c := map[id.ID]int{ id.FromString("foo.baz"): 1, id.FromString("foo.bar.baz"): 2, id.FromString("foo.bar"): 3, id.FromString("bar.baz"): 4, } c2, _ := id.MapGlob(c, id.FromString("foo.*.baz")) for k, v := range c2.(map[id.ID]int) { fmt.Println(k, v) } }
Output: foo.baz 1 foo.bar.baz 2
func SearchSlice ¶
SearchSlice finds the smallest index in haystack for which the ID at that index is greater than or equal to needle. If there is no such index, it returns len(haystack).
Example ¶
ExampleSearchSlice is a runnable example for SearchSlice.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { haystack := []id.ID{ id.FromString("fus"), id.FromString("fus.ro"), id.FromString("fus.ro.dah"), } fmt.Println(id.SearchSlice(haystack, id.ID{})) fmt.Println(id.SearchSlice(haystack, id.FromString("fus.dah"))) fmt.Println(id.SearchSlice(haystack, id.FromString("fus.ro.dah"))) fmt.Println(id.SearchSlice(haystack, id.FromString("fus.ro.dah.dah.dah"))) }
Output: 0 1 2 3
func Sort ¶
func Sort(ids []ID)
Sort sorts ids.
Example ¶
ExampleSort is a runnable example for Sort.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { ids := []id.ID{ id.FromString("arm.7"), id.FromString("arm.8"), id.FromString("ppc.64.le"), id.FromString("x86.32"), id.FromString("x86"), id.FromString("arm"), id.FromString("ppc"), id.FromString("x86.64"), id.FromString("ppc.64"), id.FromString("arm.6"), } id.Sort(ids) for _, i := range ids { fmt.Println(i) } }
Output: arm arm.6 arm.7 arm.8 ppc ppc.64 ppc.64.le x86 x86.32 x86.64
Types ¶
type ID ¶
type ID struct {
// contains filtered or unexported fields
}
ID represents a C4 ID.
func FromString ¶
FromString converts a string to a C4 ID. It returns the empty ID if there is an error.
Example ¶
ExampleFromString is a runnable example for FromString.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { fmt.Println(id.FromString("foo.bar.baz")) fmt.Println(id.FromString("FOO.BAR.BAZ")) fmt.Println(id.FromString("foo..bar.baz")) }
Output: foo.bar.baz foo.bar.baz
func LookupPrefix ¶
LookupPrefix looks up id in map m by starting from the id itself, progressively taking a smaller and smaller prefix up to and including the empty ID, and returning the first value found. If a lookup succeeded, LookupPrefix returns the matched key as key, the value as val, and true as ok; else, it returns false, and the other two values are undefined.
Example ¶
ExampleLookupPrefix is a runnable example for LookupPrefix.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { c := map[id.ID]int{ id.ID{}: 0, id.FromString("foo"): 1, id.FromString("bar"): 2, id.FromString("bar.baz"): 3, } k1, v1, _ := id.LookupPrefix(c, id.FromString("bar.baz")) k2, v2, _ := id.LookupPrefix(c, id.FromString("bar.foobaz")) k3, v3, _ := id.LookupPrefix(c, id.FromString("foo.bar.baz")) k4, v4, _ := id.LookupPrefix(c, id.FromString("baz")) fmt.Printf("matched bar.baz to %q (%d)\n", k1, v1) fmt.Printf("matched bar.foobaz to %q (%d)\n", k2, v2) fmt.Printf("matched foo.bar.baz to %q (%d)\n", k3, v3) fmt.Printf("matched baz to %q (%d)\n", k4, v4) }
Output: matched bar.baz to "bar.baz" (3) matched bar.foobaz to "bar" (2) matched foo.bar.baz to "foo" (1) matched baz to "" (0)
func MapKeys ¶
MapKeys tries to get the keys of an ID-as-string map m as a sorted list. It fails if m is not an ID-as-string map.
Example ¶
ExampleMapKeys is a runnable example for MapKeys.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { c := map[id.ID]int{ id.FromString("foo.bar"): 1, id.FromString("BAR"): 2, id.FromString("foobar.baz"): 3, id.FromString("barbaz.Foobaz"): 4, } ids, _ := id.MapKeys(c) for _, x := range ids { fmt.Println(x) } }
Output: bar barbaz.foobaz foo.bar foobar.baz
func New ¶
New tries to construct a C4 ID from tags. It fails if any of the tags is empty (unless there is only one such tag), or contains a separator.
func TryFromString ¶
TryFromString tries to convert a string to a C4 ID. It returns any validation error arising.
func (ID) Equal ¶
Equal compares two IDs for equality.
Example ¶
ExampleID_Less is a runnable example for Equal.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { fmt.Println(id.FromString("arm.7").Equal(id.FromString("arm.7"))) fmt.Println(id.FromString("arm.7").Equal(id.FromString("arm.8"))) fmt.Println(id.FromString("arm.7").Equal(id.FromString("ARM.8"))) fmt.Println(id.FromString("arm.7").Equal(id.FromString("arm"))) fmt.Println(id.ID{}.Equal(id.FromString(""))) }
Output: true false false false true
func (ID) HasPrefix ¶
HasPrefix tests whether prefix is a prefix of this ID.
Example ¶
ExampleID_HasPrefix is a runnable example for HasPrefix.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { x := id.FromString("x86.64") fmt.Println("x86.64 prefix of x86.64:", x.HasPrefix(id.FromString("x86.64"))) fmt.Println("x86 prefix of x86.64:", x.HasPrefix(id.FromString("x86"))) fmt.Println("arm prefix of x86.64:", x.HasPrefix(id.FromString("arm"))) fmt.Println("empty prefix of x86.64:", x.HasPrefix(id.ID{})) }
Output: x86.64 prefix of x86.64: true x86 prefix of x86.64: true arm prefix of x86.64: false empty prefix of x86.64: true
func (ID) HasSuffix ¶
HasSuffix tests whether suffix is a suffix of this ID.
Example ¶
ExampleID_HasSuffix is a runnable example for HasSuffix.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { x := id.FromString("x86.64") fmt.Println("x86.64 suffix of x86.64:", x.HasSuffix(id.FromString("x86.64"))) fmt.Println("64 suffix of x86.64:", x.HasSuffix(id.FromString("64"))) fmt.Println("32 suffix of x86.64:", x.HasSuffix(id.FromString("32"))) fmt.Println("empty suffix of x86.64:", x.HasSuffix(id.ID{})) }
Output: x86.64 suffix of x86.64: true 64 suffix of x86.64: true 32 suffix of x86.64: false empty suffix of x86.64: true
func (ID) IsEmpty ¶
IsEmpty gets whether this ID is empty.
Example ¶
ExampleID_IsEmpty is a runnable example for IsEmpty.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { fmt.Println(id.ID{}.IsEmpty()) fmt.Println(id.FromString("").IsEmpty()) fmt.Println(id.FromString("foo.bar.baz").IsEmpty()) }
Output: true true false
func (ID) Join ¶
Join appends r to this ID, creating a new ID.
Example ¶
ExampleID_Join is a runnable example for Join.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { id1 := id.FromString("foo.bar") id2 := id.FromString("baz.barbaz") fmt.Println(id1.Join(id2).String()) // empty IDs do nothing when joined fmt.Println(id.ID{}.Join(id1).String()) fmt.Println(id2.Join(id.ID{}).String()) }
Output: foo.bar.baz.barbaz foo.bar baz.barbaz
func (ID) Less ¶
Less compares two IDs lexicographically.
Example ¶
ExampleID_Less is a runnable example for Less.
package main import ( "fmt" "sort" "github.com/c4-project/c4t/internal/id" ) func main() { ids := []id.ID{ id.FromString("arm.7"), id.FromString("arm.8"), id.FromString("ppc.64.le"), id.FromString("x86.32"), id.FromString("x86"), id.FromString("arm"), id.FromString("ppc"), id.FromString("x86.64"), id.FromString("ppc.64"), id.FromString("arm.6"), } // Note: in general, use id.Sort instead! sort.Slice(ids, func(i, j int) bool { return ids[i].Less(ids[j]) }) for _, i := range ids { fmt.Println(i) } }
Output: arm arm.6 arm.7 arm.8 ppc ppc.64 ppc.64.le x86 x86.32 x86.64
func (ID) MarshalText ¶
MarshalText implements text marshalling for IDs by stringifying them.
func (ID) Matches ¶
Matches tests whether this ID matches the glob ID expression glob. glob should be either a literal ID, or an ID with exactly one tag equal to TagGlob.
func (ID) Tags ¶
Tags extracts the tags comprising an ID as a slice.
Example ¶
ExampleID_Tags is a runnable example for Tags.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { for _, tag := range id.FromString("foo.bar.baz").Tags() { fmt.Println(tag) } }
Output: foo bar baz
func (ID) Triple ¶
Triple splits this ID into three parts: a family tag, a variant tag, and a subvariant identifier.
Example ¶
ExampleID_Triple is a runnable example for Triple.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { f, v, s := id.ID{}.Triple() fmt.Printf("empty ID: f=%q v=%q s=%q\n", f, v, s) f, v, s = id.FromString("x86").Triple() fmt.Printf("family ID: f=%q v=%q s=%q\n", f, v, s) f, v, s = id.FromString("x86.64").Triple() fmt.Printf("variant ID: f=%q v=%q s=%q\n", f, v, s) f, v, s = id.FromString("x86.64.coffeelake").Triple() fmt.Printf("subvariant ID: f=%q v=%q s=%q\n", f, v, s) }
Output: empty ID: f="" v="" s="" family ID: f="x86" v="" s="" variant ID: f="x86" v="64" s="" subvariant ID: f="x86" v="64" s="coffeelake"
func (ID) Uncons ¶
Uncons splits an ID into a head tag and tail of zero or more further tags. If the ID is empty, ok is false, and hd and tl are unspecified.
Example ¶
ExampleID_Uncons is a runnable example for Uncons.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { _, _, ok := id.ID{}.Uncons() fmt.Println("uncons of empty ok?:", ok) // An uncons of a 1-tag ID returns that tag as the head. hd, tl, ok := id.FromString("foo").Uncons() fmt.Printf("foo: ok=%v, head=%q, tail=%q\n", ok, hd, tl) hd, tl, ok = id.FromString("foo.bar.baz").Uncons() fmt.Printf("foo.bar.baz: ok=%v, head=%q, tail=%q\n", ok, hd, tl) }
Output: uncons of empty ok?: false foo: ok=true, head="foo", tail="" foo.bar.baz: ok=true, head="foo", tail="bar.baz"
func (*ID) UnmarshalText ¶
UnmarshalText implements text unmarshalling for IDs by unstringifying them.
func (ID) Unsnoc ¶
Unsnoc splits an ID into a tail tag and head of zero or more preceding tags. If the ID is empty, ok is false, and hd and tl are unspecified.
Example ¶
ExampleID_Unsnoc is a runnable example for Unsnoc.
package main import ( "fmt" "github.com/c4-project/c4t/internal/id" ) func main() { _, _, ok := id.ID{}.Unsnoc() fmt.Println("unsnoc of empty ok?:", ok) // An unsnoc of a 1-tag ID returns that tag as the tail. hd, tl, ok := id.FromString("foo").Unsnoc() fmt.Printf("foo: ok=%v, head=%q, tail=%q\n", ok, hd, tl) hd, tl, ok = id.FromString("foo.bar.baz").Unsnoc() fmt.Printf("foo.bar.baz: ok=%v, head=%q, tail=%q\n", ok, hd, tl) }
Output: unsnoc of empty ok?: false foo: ok=true, head="", tail="foo" foo.bar.baz: ok=true, head="foo.bar", tail="baz"