libero/field_type

The structured Gleam type representation libero uses for both shared-type discovery (walker) and handler signature scanning (scanner). Lifting it out of either module lets both produce and consume the same shape, and lets codegen pattern-match structurally instead of re-parsing strings.

Types

A Gleam type, resolved to a structured form. Module-qualified references (e.g. types.Item written in user code) are resolved to their canonical module path (e.g. shared/types) at production time; downstream consumers can rely on module_path being the import-stable name without re-doing alias resolution.

pub type FieldType {
  UserType(
    module_path: String,
    type_name: String,
    args: List(FieldType),
  )
  ListOf(element: FieldType)
  OptionOf(inner: FieldType)
  ResultOf(ok: FieldType, err: FieldType)
  DictOf(key: FieldType, value: FieldType)
  TupleOf(elements: List(FieldType))
  IntField
  FloatField
  StringField
  BoolField
  BitArrayField
  NilField
  TypeVar(name: String)
}

Constructors

  • UserType(
      module_path: String,
      type_name: String,
      args: List(FieldType),
    )
  • ListOf(element: FieldType)
  • OptionOf(inner: FieldType)
  • ResultOf(ok: FieldType, err: FieldType)
  • DictOf(key: FieldType, value: FieldType)
  • TupleOf(elements: List(FieldType))
  • IntField
  • FloatField
  • StringField
  • BoolField
  • BitArrayField
  • NilField
  • TypeVar(name: String)

    A type variable (generic parameter) that survives to runtime. Cannot be encoded over the wire; codegen emits a runtime error.

Values

pub fn builtin_field_type(
  name name: String,
  parameters parameters: List(a),
  recurse recurse: fn(a) -> FieldType,
) -> Result(FieldType, Nil)

Map a builtin Gleam type name (and its parameters) to the corresponding FieldType. Returns Error(Nil) when the name isn’t a recognised builtin or the parameter arity doesn’t match. The caller supplies recurse to convert each parameter (typically a glance.Type) into a FieldType, keeping this module independent of glance. Used by scanner and walker so the builtin dispatch lives in one place.

pub const builtin_type_names: List(String)

Names of Gleam types that libero treats as builtin: not user-defined, not requiring atom registration, and not from the shared/ tree. Both the scanner and the walker consult this list, so they agree on what counts as a primitive across the codegen pipeline.

Note: Tuples are not in this list because they are structural types (glance.TupleType), not named types (glance.NamedType). They’re handled by direct pattern matching in scanner and walker rather than through builtin_field_type. The two paths converge on TupleOf.

pub fn collect_user_types(
  ft: FieldType,
) -> List(#(String, String))

Walk a FieldType and collect every UserType reference it contains (including transitive ones). Returns #(module_path, type_name) tuples in discovery order. Used by codegen to determine which shared modules to import.

pub fn contains(
  ft: FieldType,
  predicate: fn(FieldType) -> Bool,
) -> Bool

True if predicate returns True for ft or any FieldType nested within it. Used by codegen to ask questions like “does this type transitively contain Option?” without substring-scanning.

pub fn is_builtin(name: String) -> Bool

True if name is one of the builtin Gleam type names libero recognises.

pub fn last_segment(module_path: String) -> String

Last /-separated segment of a module path, or the path itself if no separator is present. Used wherever codegen needs the “short” module name for aliases or display.

pub fn to_canonical_token(ft: FieldType) -> String

Render a FieldType to its canonical hash-basis token. Used by wire_identity.canonical_signature to build the deterministic string that feeds the wire-identity hash.

The canonical token is purely structural: it captures the type’s shape in a form that is stable across compilations and across tooling. A renamed field preserves the token (only types appear), but a retyped field changes it. UserType references render as <type:module|name> with no transitive hash, which keeps recursive and mutually-recursive types finite and side-steps cycle resolution entirely.

Format reference (excerpt from the wire-type-identity spec): IntField -> “int” FloatField -> “float” ListOf(t) -> “list<>” ResultOf(o, e) -> “result<,>” UserType(m,n,_) -> “type:m|n” (zero-arg) UserType(m,n,a) -> “<type:m|n<>>” (applied generic)

TypeVars survive to runtime as encoding errors in real wire types; rendered here as “typevar:name” so the canonical signature stays well-formed even for in-progress type definitions.

pub fn to_gleam_source(ft: FieldType) -> String

Render a FieldType as the user-readable Gleam type syntax it came from. UserType uses the LAST segment of the module path so the output matches what the user originally wrote (e.g. types.Item, not shared/types.Item). Used by codegen to embed types in generated Gleam source.

pub fn to_gleam_source_with_alias(
  ft: FieldType,
  resolve_alias: fn(String) -> String,
) -> String

Like to_gleam_source but uses a caller-supplied function to resolve the import alias for a module path. This allows codegen to provide disambiguated aliases when multiple modules share the same last segment (e.g. two different id_ modules).

Search Document