bytescty

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: BSD-2-Clause Imports: 8 Imported by: 0

README

bytes-cty-type

A go-cty capsule type for immutable byte slices with optional MIME content types, plus functions for encoding and decoding.

CI

Overview

This package provides a bytes type for use in HCL2 / cty expression evaluation contexts. A bytes value carries raw binary data and an optional content type string. It is represented as a cty object with a content_type attribute and an internal _capsule attribute for interface dispatch.

Extracted from vinculum, where it powers binary payloads in HTTP, serialization, and key-value store operations.

Types

bytescty.Bytes
type Bytes struct {
    Data        []byte
    ContentType string
}
bytescty.BytesCapsuleType

A cty capsule type wrapping *Bytes. Used internally as the _capsule attribute of bytes objects.

bytescty.BytesObjectType

A cty object type with attributes:

  • content_type (string) — the MIME type
  • _capsule (BytesCapsuleType) — the encapsulated bytes
Helper functions
bytescty.NewBytesCapsule(data []byte, contentType string) cty.Value
bytescty.BuildBytesObject(data []byte, contentType string) cty.Value
bytescty.GetBytesFromCapsule(val cty.Value) (*Bytes, error)
bytescty.GetBytesFromValue(val cty.Value) (*Bytes, error)

GetBytesFromValue accepts a raw capsule, a bytes object, or any cty object with a _capsule attribute containing a *Bytes — it delegates to rich-cty-types GetCapsuleFromValue.

Registration

import bytescty "github.com/tsarna/bytes-cty-type"

// Add all bytes functions to your eval context:
for name, fn := range bytescty.GetBytesFunctions() {
    funcs[name] = fn
}
rich-cty-types integration

The Bytes type implements the rich-cty-types Stringable and Lengthable interfaces:

  • tostring(b) returns the raw bytes as a UTF-8 string.
  • length(b) returns the byte length.
import (
    bytescty "github.com/tsarna/bytes-cty-type"
    richcty  "github.com/tsarna/rich-cty-types"
)

funcs := richcty.GetGenericFunctions()           // tostring, length, ...
for name, fn := range bytescty.GetBytesFunctions() {
    funcs[name] = fn
}

Functions

Function Signature Description
bytes(s) (string) → bytes Create bytes from a UTF-8 string
bytes(s, ct) (string, string) → bytes Create bytes with a content type
bytes(b) (bytes) → bytes Copy a bytes value (preserves content type)
bytes(b, ct) (bytes, string) → bytes Copy with overridden content type
base64encode(v) (string|bytes) → string Encode a string or bytes value to base64
base64decode(s) (string) → string Decode base64 to string (backward compatible)
base64decode(s, ct) (string, string) → bytes Decode base64 to bytes object with content type

base64encode and base64decode deliberately shadow the HCL builtins of the same name, extending them rather than replacing them: one-argument base64decode still returns a string, so config written against the builtin keeps working.

Signature declarations

The table above is what these functions really accept. It is not what their cty metadata can say, and the gap is not small:

  • Each takes an argument that is a union — a string, or a bytes value. cty has no union type, so its metadata can only say dynamic.
  • bytes and base64decode each take one optional trailing argument. The only way cty offers to make an argument optional is to make it variadic, which erases its name, its type, and its arity.
  • base64decode's return type depends on whether that argument is present — string with one argument, bytes with two — and a cty function has exactly one signature to say it in.

So externs.cty declares the real signatures, as functy //functy:extern declarations. The file is never compiled and declares nothing callable; it exists so that help(), generated documentation, and editor tooling can show what the cty metadata cannot.

Externs() returns it as opaque bytes — this package does not import functy and does not parse them:

parser.RegisterExterns(bytescty.Externs(), bytescty.ExternsFilename)

A host that is not a functy host can ignore it entirely; the cty Description on every function and parameter is still populated.

Examples

# Create bytes from a string
bytes("hello world")
bytes("hello", "text/plain")

# Access content type
bytes("img data", "image/png").content_type   # "image/png"

# Base64 round-trip
base64encode("hello")                          # "aGVsbG8="
base64decode("aGVsbG8=")                       # "hello" (string)
base64decode("aGVsbG8=", "text/plain")         # bytes object

# Re-wrap with different content type
bytes(existing_bytes, "application/json")

# With rich-cty-types generic functions
tostring(b)                                    # raw bytes as string
length(b)                                      # byte count

License

BSD 2-Clause — see LICENSE.

Documentation

Index

Constants

View Source
const ExternsFilename = "bytes-cty-type/externs.cty"

ExternsFilename is the name reported for the embedded declarations in diagnostics.

Variables

View Source
var BytesCapsuleType = cty.CapsuleWithOps("bytes", reflect.TypeOf(Bytes{}), &cty.CapsuleOps{
	GoString: func(val interface{}) string {
		b := val.(*Bytes)
		return fmt.Sprintf("bytes(%d bytes)", len(b.Data))
	},
	TypeGoString: func(_ reflect.Type) string {
		return "Bytes"
	},
})

BytesCapsuleType is the cty capsule type for Bytes values.

View Source
var BytesObjectType = cty.Object(map[string]cty.Type{
	"content_type": cty.String,
	"_capsule":     BytesCapsuleType,
})

BytesObjectType is the cty object type returned by bytes-producing functions. It exposes content_type as a direct attribute and carries the underlying capsule in the _capsule attribute for interface dispatch (richcty.Stringable, richcty.Lengthable, etc.).

Functions

func BuildBytesObject

func BuildBytesObject(data []byte, contentType string) cty.Value

BuildBytesObject returns a cty object with content_type and _capsule attributes.

func Externs added in v0.2.0

func Externs() []byte

Externs returns the functy `//functy:extern` declarations for the functions GetBytesFunctions provides: their real signatures, which their cty metadata cannot express.

All three take an argument that is a union — a string, or a bytes value — and cty has no union type, so its metadata can only say "dynamic". Two of them also take an optional trailing content type, and cty can only make an argument optional by making it variadic, which erases its name, its type, and its arity; for base64decode, whose return type is a string or a bytes value depending on whether that argument is present, it erases the signature entirely. These declarations say what each really accepts, so that help(), generated documentation, and editor tooling can show it.

The bytes are opaque to this package: it does not import functy, and nothing here parses them. A functy host registers them:

parser.RegisterExterns(bytescty.Externs(), bytescty.ExternsFilename)

func GetBytesFunctions

func GetBytesFunctions() map[string]function.Function

GetBytesFunctions returns bytes-related cty functions for registration in an eval context.

func MakeBase64DecodeFunc

func MakeBase64DecodeFunc() function.Function

MakeBase64DecodeFunc returns a base64decode function.

When called with one argument it returns a string, preserving backward compatibility with the stdlib version. When a second (content_type) argument is present — even if it is the empty string — it returns a bytes object.

base64decode(str)                - returns string (backward compatible)
base64decode(str, "")            - returns bytes object, no content type
base64decode(str, "image/png")   - returns bytes object with content type

func MakeBase64EncodeFunc

func MakeBase64EncodeFunc() function.Function

MakeBase64EncodeFunc returns a base64encode function that accepts either a string or bytes value.

func MakeBytesFunc

func MakeBytesFunc() function.Function

MakeBytesFunc returns a function that creates a bytes object from a UTF-8 string or re-wraps an existing bytes value with a different content type.

bytes(str)               - bytes from UTF-8 string, no content type
bytes(str, content_type) - bytes from UTF-8 string with content type
bytes(b)                 - copy of bytes value (preserves content type)
bytes(b, content_type)   - copy of bytes value with overridden content type

func NewBytesCapsule

func NewBytesCapsule(data []byte, contentType string) cty.Value

NewBytesCapsule wraps a byte slice and optional content type in a cty capsule value.

Types

type Bytes

type Bytes struct {
	Data        []byte
	ContentType string
}

Bytes is an immutable byte slice with an optional content/MIME type.

func GetBytesFromCapsule

func GetBytesFromCapsule(val cty.Value) (*Bytes, error)

GetBytesFromCapsule extracts a *Bytes from a cty capsule value.

func GetBytesFromValue

func GetBytesFromValue(val cty.Value) (*Bytes, error)

GetBytesFromValue extracts a *Bytes from a bytes object, capsule, or anything accepted by GetCapsuleFromValue.

func (*Bytes) Length

func (b *Bytes) Length(_ context.Context) (int64, error)

Length implements richcty.Lengthable, returning the byte length.

func (*Bytes) ToString

func (b *Bytes) ToString(_ context.Context) (string, error)

ToString implements richcty.Stringable, returning the bytes data as a UTF-8 string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL