-
Notifications
You must be signed in to change notification settings - Fork 16
/
code.go
88 lines (77 loc) · 3 KB
/
code.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Package multicodec exposes the multicodec table as Go constants.
package multicodec
import (
"flag"
"fmt"
"strconv"
)
//go:generate go run gen.go
//go:generate gofmt -w code_table.go
//go:generate go run golang.org/x/tools/cmd/stringer@v0.24.0 -type=Code -linecomment
// Code describes an integer reserved in the multicodec table, defined at
// github.com/multiformats/multicodec.
type Code uint64
// Assert that Code implements flag.Value.
// Requires a pointer, since Set modifies the receiver.
//
// Note that we don't implement encoding.TextMarshaler and encoding.TextUnmarshaler.
// That's on purpose; even though multicodec names are stable just like the codes,
// Go should still generally encode and decode multicodecs by their code number.
// Many encoding libraries like xml and json default to TextMarshaler if it exists.
//
// Conversely, implementing flag.Value makes sense;
// --someflag=sha1 is useful as it would often be typed by a human.
var _ flag.Value = (*Code)(nil)
// Assert that Code implements fmt.Stringer without a pointer.
var _ fmt.Stringer = Code(0)
// ReservedStart is the (inclusive) start of the reserved range of codes that
// are safe to use for internal purposes.
const ReservedStart = 0x300000
// ReservedEnd is the (inclusive) end of the reserved range of codes that are
// safe to use for internal purposes.
const ReservedEnd = 0x3FFFFF
// Set implements flag.Value, interpreting the input string as a multicodec and
// setting the receiver to it.
//
// The input string can be the name or number for a known code. A number can be
// in any format accepted by strconv.ParseUint with base 0, including decimal
// and hexadecimal.
//
// Numbers in the reserved range 0x300000-0x3FFFFF are also accepted.
func (c *Code) Set(text string) error {
// Checking if the text is a valid number is cheap, so do it first.
// It should be impossible for a string to be both a valid number and a
// valid name, anyway.
if n, err := strconv.ParseUint(text, 0, 64); err == nil {
code := Code(n)
if code >= 0x300000 && code <= 0x3FFFFF { // reserved range
*c = code
return nil
}
if _, ok := _Code_map[code]; ok { // known code
*c = code
return nil
}
}
// For now, checking if the text is a valid name is a linear operation,
// so do it after.
// Right now we have ~450 codes, so a linear search isn't too bad.
// Consider generating a map[string]Code later on if linear search
// starts being a problem.
for code, name := range _Code_map {
if name == text {
*c = code
return nil
}
}
return fmt.Errorf("unknown multicodec: %q", text)
}
// Note that KnownCodes is a function backed by a code-generated slice.
// Later on, if the slice gets too large, we could codegen a packed form
// and only expand to a regular slice via a sync.Once.
// A function also makes it a bit clearer that the list should be read-only.
// KnownCodes returns a list of all codes registered in the multicodec table.
// The returned slice should be treated as read-only.
func KnownCodes() []Code {
return knownCodes
}