]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package stdlib |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | "reflect" | |
6 | ||
7 | "github.com/zclconf/go-cty/cty" | |
8 | "github.com/zclconf/go-cty/cty/function" | |
9 | "github.com/zclconf/go-cty/cty/gocty" | |
10 | ) | |
11 | ||
12 | // Bytes is a capsule type that can be used with the binary functions to | |
13 | // support applications that need to support raw buffers in addition to | |
14 | // UTF-8 strings. | |
15 | var Bytes = cty.Capsule("bytes", reflect.TypeOf([]byte(nil))) | |
16 | ||
17 | // BytesVal creates a new Bytes value from the given buffer, which must be | |
18 | // non-nil or this function will panic. | |
19 | // | |
20 | // Once a byte slice has been wrapped in a Bytes capsule, its underlying array | |
21 | // must be considered immutable. | |
22 | func BytesVal(buf []byte) cty.Value { | |
23 | if buf == nil { | |
24 | panic("can't make Bytes value from nil slice") | |
25 | } | |
26 | ||
27 | return cty.CapsuleVal(Bytes, &buf) | |
28 | } | |
29 | ||
30 | // BytesLen is a Function that returns the length of the buffer encapsulated | |
31 | // in a Bytes value. | |
32 | var BytesLenFunc = function.New(&function.Spec{ | |
33 | Params: []function.Parameter{ | |
34 | { | |
35 | Name: "buf", | |
36 | Type: Bytes, | |
37 | AllowDynamicType: true, | |
38 | }, | |
39 | }, | |
40 | Type: function.StaticReturnType(cty.Number), | |
41 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | |
42 | bufPtr := args[0].EncapsulatedValue().(*[]byte) | |
43 | return cty.NumberIntVal(int64(len(*bufPtr))), nil | |
44 | }, | |
45 | }) | |
46 | ||
47 | // BytesSlice is a Function that returns a slice of the given Bytes value. | |
48 | var BytesSliceFunc = function.New(&function.Spec{ | |
49 | Params: []function.Parameter{ | |
50 | { | |
51 | Name: "buf", | |
52 | Type: Bytes, | |
53 | AllowDynamicType: true, | |
54 | }, | |
55 | { | |
56 | Name: "offset", | |
57 | Type: cty.Number, | |
58 | AllowDynamicType: true, | |
59 | }, | |
60 | { | |
61 | Name: "length", | |
62 | Type: cty.Number, | |
63 | AllowDynamicType: true, | |
64 | }, | |
65 | }, | |
66 | Type: function.StaticReturnType(Bytes), | |
67 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | |
68 | bufPtr := args[0].EncapsulatedValue().(*[]byte) | |
69 | ||
70 | var offset, length int | |
71 | ||
72 | var err error | |
73 | err = gocty.FromCtyValue(args[1], &offset) | |
74 | if err != nil { | |
75 | return cty.NilVal, err | |
76 | } | |
77 | err = gocty.FromCtyValue(args[2], &length) | |
78 | if err != nil { | |
79 | return cty.NilVal, err | |
80 | } | |
81 | ||
82 | if offset < 0 || length < 0 { | |
83 | return cty.NilVal, fmt.Errorf("offset and length must be non-negative") | |
84 | } | |
85 | ||
86 | if offset > len(*bufPtr) { | |
87 | return cty.NilVal, fmt.Errorf( | |
88 | "offset %d is greater than total buffer length %d", | |
89 | offset, len(*bufPtr), | |
90 | ) | |
91 | } | |
92 | ||
93 | end := offset + length | |
94 | ||
95 | if end > len(*bufPtr) { | |
96 | return cty.NilVal, fmt.Errorf( | |
97 | "offset %d + length %d is greater than total buffer length %d", | |
98 | offset, length, len(*bufPtr), | |
99 | ) | |
100 | } | |
101 | ||
102 | return BytesVal((*bufPtr)[offset:end]), nil | |
103 | }, | |
104 | }) | |
105 | ||
106 | func BytesLen(buf cty.Value) (cty.Value, error) { | |
107 | return BytesLenFunc.Call([]cty.Value{buf}) | |
108 | } | |
109 | ||
110 | func BytesSlice(buf cty.Value, offset cty.Value, length cty.Value) (cty.Value, error) { | |
111 | return BytesSliceFunc.Call([]cty.Value{buf, offset, length}) | |
112 | } |