| package stdlib |
| |
| import ( |
| "fmt" |
| "reflect" |
| |
| "github.com/zclconf/go-cty/cty" |
| "github.com/zclconf/go-cty/cty/function" |
| "github.com/zclconf/go-cty/cty/gocty" |
| ) |
| |
| // Bytes is a capsule type that can be used with the binary functions to |
| // support applications that need to support raw buffers in addition to |
| // UTF-8 strings. |
| var Bytes = cty.Capsule("bytes", reflect.TypeOf([]byte(nil))) |
| |
| // BytesVal creates a new Bytes value from the given buffer, which must be |
| // non-nil or this function will panic. |
| // |
| // Once a byte slice has been wrapped in a Bytes capsule, its underlying array |
| // must be considered immutable. |
| func BytesVal(buf []byte) cty.Value { |
| if buf == nil { |
| panic("can't make Bytes value from nil slice") |
| } |
| |
| return cty.CapsuleVal(Bytes, &buf) |
| } |
| |
| // BytesLen is a Function that returns the length of the buffer encapsulated |
| // in a Bytes value. |
| var BytesLenFunc = function.New(&function.Spec{ |
| Params: []function.Parameter{ |
| { |
| Name: "buf", |
| Type: Bytes, |
| AllowDynamicType: true, |
| }, |
| }, |
| Type: function.StaticReturnType(cty.Number), |
| Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { |
| bufPtr := args[0].EncapsulatedValue().(*[]byte) |
| return cty.NumberIntVal(int64(len(*bufPtr))), nil |
| }, |
| }) |
| |
| // BytesSlice is a Function that returns a slice of the given Bytes value. |
| var BytesSliceFunc = function.New(&function.Spec{ |
| Params: []function.Parameter{ |
| { |
| Name: "buf", |
| Type: Bytes, |
| AllowDynamicType: true, |
| }, |
| { |
| Name: "offset", |
| Type: cty.Number, |
| AllowDynamicType: true, |
| }, |
| { |
| Name: "length", |
| Type: cty.Number, |
| AllowDynamicType: true, |
| }, |
| }, |
| Type: function.StaticReturnType(Bytes), |
| Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { |
| bufPtr := args[0].EncapsulatedValue().(*[]byte) |
| |
| var offset, length int |
| |
| var err error |
| err = gocty.FromCtyValue(args[1], &offset) |
| if err != nil { |
| return cty.NilVal, err |
| } |
| err = gocty.FromCtyValue(args[2], &length) |
| if err != nil { |
| return cty.NilVal, err |
| } |
| |
| if offset < 0 || length < 0 { |
| return cty.NilVal, fmt.Errorf("offset and length must be non-negative") |
| } |
| |
| if offset > len(*bufPtr) { |
| return cty.NilVal, fmt.Errorf( |
| "offset %d is greater than total buffer length %d", |
| offset, len(*bufPtr), |
| ) |
| } |
| |
| end := offset + length |
| |
| if end > len(*bufPtr) { |
| return cty.NilVal, fmt.Errorf( |
| "offset %d + length %d is greater than total buffer length %d", |
| offset, length, len(*bufPtr), |
| ) |
| } |
| |
| return BytesVal((*bufPtr)[offset:end]), nil |
| }, |
| }) |
| |
| func BytesLen(buf cty.Value) (cty.Value, error) { |
| return BytesLenFunc.Call([]cty.Value{buf}) |
| } |
| |
| func BytesSlice(buf cty.Value, offset cty.Value, length cty.Value) (cty.Value, error) { |
| return BytesSliceFunc.Call([]cty.Value{buf, offset, length}) |
| } |