Current section

Files

Jump to
libero src libero@etf@codegen_erl.erl
Raw

src/libero@etf@codegen_erl.erl

-module(libero@etf@codegen_erl).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/libero/etf/codegen_erl.gleam").
-export([generate/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Codegen for the per-consumer wire-transformers Erlang module.\n"
"\n"
" Emits one Erlang module per consumer (e.g. `<consumer>_wire.erl`)\n"
" containing per-type `encode_<type>/1` and `decode_<type>/1`\n"
" functions. These translate between BEAM-shape (bare atom tags from\n"
" Gleam constructors) and wire-shape (hashed atoms from\n"
" `wire_identity.wire_hash`).\n"
"\n"
" The wire identity for each variant is the SHA-256-based hash from\n"
" `wire_identity.wire_identity`, computed at codegen time and baked\n"
" into the generated tuple tag. The runtime carries no global lookup\n"
" tables for type identity.\n"
"\n"
" Function names use `walker.qualified_atom_name` so that two\n"
" modules with same-named types produce distinct transformer\n"
" functions in the same Erlang module. The wire atom on the\n"
" generated tuple is the 10-char hash; the function name is the\n"
" codegen-internal symbol used for cross-type recursion.\n"
).
-file("src/libero/etf/codegen_erl.gleam", 114).
-spec float_helper_source() -> binary().
float_helper_source() ->
<<"%% Ensure whole-number floats stay floats on the wire. JS erases the
%% Int/Float distinction at runtime; this normalisation on the BEAM
%% side preserves wire-format type fidelity end-to-end.
encode_float(F) when is_float(F) -> F;
encode_float(N) when is_integer(N) -> N + 0.0."/utf8>>.
-file("src/libero/etf/codegen_erl.gleam", 122).
-spec type_function_atom(libero@walker:discovered_type()) -> binary().
type_function_atom(Dt) ->
libero@walker:qualified_atom_name(
erlang:element(2, Dt),
erlang:element(3, Dt)
).
-file("src/libero/etf/codegen_erl.gleam", 306).
-spec wire_hash_for_variant(libero@walker:discovered_variant()) -> binary().
wire_hash_for_variant(V) ->
{_, Hash} = libero@wire_identity:wire_identity(
erlang:element(2, V),
erlang:element(3, V),
erlang:element(7, V)
),
Hash.
-file("src/libero/etf/codegen_erl.gleam", 140).
-spec emit_decode_term(list(libero@walker:discovered_type())) -> binary().
emit_decode_term(Discovered) ->
Atom_clauses = gleam@list:flat_map(
Discovered,
fun(Dt) ->
gleam@list:filter_map(
erlang:element(5, Dt),
fun(V) -> case erlang:element(7, V) of
[] ->
Bare = libero@walker:to_snake_case(
erlang:element(3, V)
),
Hash = wire_hash_for_variant(V),
{ok,
<<<<<<" '"/utf8, Hash/binary>>/binary,
"' -> "/utf8>>/binary,
Bare/binary>>};
_ ->
{error, nil}
end end
)
end
),
Tuple_clauses = gleam@list:flat_map(
Discovered,
fun(Dt@1) ->
gleam@list:filter_map(
erlang:element(5, Dt@1),
fun(V@1) -> case erlang:element(7, V@1) of
[] ->
{error, nil};
Fields ->
Hash@1 = wire_hash_for_variant(V@1),
Arity = erlang:integer_to_binary(
erlang:length(Fields) + 1
),
Type_atom = type_function_atom(Dt@1),
{ok,
<<<<<<<<<<<<" {'"/utf8, Hash@1/binary>>/binary,
"', "/utf8>>/binary,
Arity/binary>>/binary,
"} -> decode_"/utf8>>/binary,
Type_atom/binary>>/binary,
"(Tuple, Depth + 1)"/utf8>>}
end end
)
end
),
Atom_case = case Atom_clauses of
[] ->
<<""/utf8>>;
_ ->
<<<<"decode_term(Atom, _Depth) when is_atom(Atom) ->\n case Atom of\n"/utf8,
(gleam@string:join(Atom_clauses, <<";\n"/utf8>>))/binary>>/binary,
";\n Other -> Other\n end;\n"/utf8>>
end,
Tuple_case = <<"decode_term(Tuple, Depth) when is_tuple(Tuple), tuple_size(Tuple) > 0 ->\n"/utf8,
(case Tuple_clauses of
[] ->
<<" list_to_tuple([decode_term(E, Depth + 1) || E <- tuple_to_list(Tuple)]);\n"/utf8>>;
_ ->
<<<<" case {element(1, Tuple), tuple_size(Tuple)} of\n"/utf8,
(gleam@string:join(Tuple_clauses, <<";\n"/utf8>>))/binary>>/binary,
";\n _ -> list_to_tuple([decode_term(E, Depth + 1) || E <- tuple_to_list(Tuple)])\n end;\n"/utf8>>
end)/binary>>,
<<<<<<<<<<<<"decode_term(Term) -> decode_term(Term, 0).\n\n"/utf8,
"decode_term(_Term, Depth) when Depth >= 512 ->\n error({wire_depth_exceeded, Depth});\n"/utf8>>/binary,
Atom_case/binary>>/binary,
Tuple_case/binary>>/binary,
"decode_term(List, Depth) when is_list(List) ->\n [decode_term(X, Depth + 1) || X <- List];\n"/utf8>>/binary,
"decode_term(Map, Depth) when is_map(Map) ->\n maps:map(fun(_K, V) -> decode_term(V, Depth + 1) end, Map);\n"/utf8>>/binary,
"decode_term(Other, _Depth) -> Other."/utf8>>.
-file("src/libero/etf/codegen_erl.gleam", 129).
-spec emit_encode_term(list(libero@walker:discovered_type())) -> binary().
emit_encode_term(_) ->
<<"encode_term(Term) -> encode_term(Term, 0).\n\nencode_term(_Term, Depth) when Depth >= 512 ->\n error({wire_depth_exceeded, Depth});\nencode_term(Tuple, Depth) when is_tuple(Tuple), tuple_size(Tuple) > 0 ->\n list_to_tuple([encode_term(E, Depth + 1) || E <- tuple_to_list(Tuple)]);\nencode_term(List, Depth) when is_list(List) ->\n [encode_term(X, Depth + 1) || X <- List];\nencode_term(Map, Depth) when is_map(Map) ->\n maps:map(fun(_K, V) -> encode_term(V, Depth + 1) end, Map);\nencode_term(Other, _Depth) -> Other."/utf8>>.
-file("src/libero/etf/codegen_erl.gleam", 302).
-spec next_runtime_depth(binary()) -> binary().
next_runtime_depth(Runtime_depth) ->
<<Runtime_depth/binary, " + 1"/utf8>>.
-file("src/libero/etf/codegen_erl.gleam", 280).
-spec fresh_var(integer()) -> binary().
fresh_var(Depth) ->
<<"_X"/utf8, (erlang:integer_to_binary(Depth))/binary>>.
-file("src/libero/etf/codegen_erl.gleam", 434).
?DOC(
" Render the Erlang expression that decodes a wire value (bound to\n"
" `expr`) into BEAM shape. Mirror image of `encode_expr`.\n"
).
-spec decode_expr(libero@field_type:field_type(), binary(), integer(), binary()) -> binary().
decode_expr(Field_type, Expr, Name_depth, Runtime_depth) ->
Inner_var = fresh_var(Name_depth),
case Field_type of
int_field ->
Expr;
string_field ->
Expr;
bool_field ->
Expr;
bit_array_field ->
Expr;
nil_field ->
Expr;
float_field ->
Expr;
{user_type, Module_path, Type_name, _} ->
Qual = libero@walker:qualified_atom_name(Module_path, Type_name),
<<<<<<<<<<<<"decode_"/utf8, Qual/binary>>/binary, "("/utf8>>/binary,
Expr/binary>>/binary,
", "/utf8>>/binary,
(next_runtime_depth(Runtime_depth))/binary>>/binary,
")"/utf8>>;
{list_of, Element} ->
Inner = decode_expr(
Element,
Inner_var,
Name_depth + 1,
next_runtime_depth(Runtime_depth)
),
case Inner =:= Inner_var of
true ->
Expr;
false ->
<<<<<<<<<<<<"["/utf8, Inner/binary>>/binary, " || "/utf8>>/binary,
Inner_var/binary>>/binary,
" <- "/utf8>>/binary,
Expr/binary>>/binary,
"]"/utf8>>
end;
{option_of, Inner@1} ->
Body = decode_expr(
Inner@1,
Inner_var,
Name_depth + 1,
next_runtime_depth(Runtime_depth)
),
case Body =:= Inner_var of
true ->
Expr;
false ->
<<<<<<<<<<<<"case "/utf8, Expr/binary>>/binary,
" of {some, "/utf8>>/binary,
Inner_var/binary>>/binary,
"} -> {some, "/utf8>>/binary,
Body/binary>>/binary,
"}; none -> none end"/utf8>>
end;
{result_of, Ok, Err} ->
Err_var = <<"_E"/utf8,
(erlang:integer_to_binary(Name_depth))/binary>>,
Ok_body = decode_expr(
Ok,
Inner_var,
Name_depth + 1,
next_runtime_depth(Runtime_depth)
),
Err_body = decode_expr(
Err,
Err_var,
Name_depth + 1,
next_runtime_depth(Runtime_depth)
),
case (Ok_body =:= Inner_var) andalso (Err_body =:= Err_var) of
true ->
Expr;
false ->
<<<<<<<<<<<<<<<<<<<<"case "/utf8, Expr/binary>>/binary,
" of {ok, "/utf8>>/binary,
Inner_var/binary>>/binary,
"} -> {ok, "/utf8>>/binary,
Ok_body/binary>>/binary,
"}; {error, "/utf8>>/binary,
Err_var/binary>>/binary,
"} -> {error, "/utf8>>/binary,
Err_body/binary>>/binary,
"} end"/utf8>>
end;
{dict_of, _, Value} ->
Body@1 = decode_expr(
Value,
Inner_var,
Name_depth + 1,
next_runtime_depth(Runtime_depth)
),
case Body@1 =:= Inner_var of
true ->
Expr;
false ->
<<<<<<<<<<<<"maps:map(fun(_K, "/utf8, Inner_var/binary>>/binary,
") -> "/utf8>>/binary,
Body@1/binary>>/binary,
" end, "/utf8>>/binary,
Expr/binary>>/binary,
")"/utf8>>
end;
{tuple_of, Elements} ->
Indexed = gleam@list:index_map(
Elements,
fun(Element@1, Index) ->
{Element@1,
<<<<<<"_T"/utf8,
(erlang:integer_to_binary(Name_depth))/binary>>/binary,
"_"/utf8>>/binary,
(erlang:integer_to_binary(Index))/binary>>}
end
),
Bind_vars = gleam@list:map(
Indexed,
fun(Pair) -> erlang:element(2, Pair) end
),
Body_terms = gleam@list:map(
Indexed,
fun(Pair@1) ->
decode_expr(
erlang:element(1, Pair@1),
erlang:element(2, Pair@1),
Name_depth + 1,
next_runtime_depth(Runtime_depth)
)
end
),
case Body_terms =:= Bind_vars of
true ->
Expr;
false ->
<<<<<<<<<<<<"case "/utf8, Expr/binary>>/binary,
" of {"/utf8>>/binary,
(gleam@string:join(Bind_vars, <<", "/utf8>>))/binary>>/binary,
"} -> {"/utf8>>/binary,
(gleam@string:join(Body_terms, <<", "/utf8>>))/binary>>/binary,
"} end"/utf8>>
end;
{type_var, Name} ->
<<<<"erlang:error({wire_typevar_not_supported, <<\""/utf8,
Name/binary>>/binary,
"\">>})"/utf8>>
end.
-file("src/libero/etf/codegen_erl.gleam", 284).
-spec needs_runtime_depth(libero@field_type:field_type()) -> boolean().
needs_runtime_depth(Field_type) ->
case Field_type of
int_field ->
false;
string_field ->
false;
bool_field ->
false;
bit_array_field ->
false;
nil_field ->
false;
float_field ->
false;
{user_type, _, _, _} ->
true;
{list_of, Element} ->
needs_runtime_depth(Element);
{option_of, Inner} ->
needs_runtime_depth(Inner);
{result_of, Ok, Err} ->
needs_runtime_depth(Ok) orelse needs_runtime_depth(Err);
{dict_of, _, Value} ->
needs_runtime_depth(Value);
{tuple_of, Elements} ->
gleam@list:any(Elements, fun needs_runtime_depth/1);
{type_var, _} ->
true
end.
-file("src/libero/etf/codegen_erl.gleam", 276).
-spec top_var(integer()) -> binary().
top_var(I) ->
<<"F"/utf8, (erlang:integer_to_binary(I))/binary>>.
-file("src/libero/etf/codegen_erl.gleam", 239).
-spec emit_decode_clause(libero@walker:discovered_variant(), binary()) -> binary().
emit_decode_clause(V, Type_atom) ->
Bare = libero@walker:to_snake_case(erlang:element(3, V)),
Hash = wire_hash_for_variant(V),
case erlang:element(7, V) of
[] ->
<<<<<<<<<<"decode_"/utf8, Type_atom/binary>>/binary, "('"/utf8>>/binary,
Hash/binary>>/binary,
"', _Depth) ->\n "/utf8>>/binary,
Bare/binary>>;
Fields ->
Indexed = gleam@list:index_map(
Fields,
fun(Ft, I) -> {Ft, top_var(I)} end
),
Pattern_vars = gleam@list:map(
Indexed,
fun(P) -> erlang:element(2, P) end
),
Pattern = <<<<<<<<"{'"/utf8, Hash/binary>>/binary, "', "/utf8>>/binary,
(gleam@string:join(Pattern_vars, <<", "/utf8>>))/binary>>/binary,
"}"/utf8>>,
Depth_var = case gleam@list:any(Fields, fun needs_runtime_depth/1) of
true ->
<<"Depth"/utf8>>;
false ->
<<"_Depth"/utf8>>
end,
Body_terms = gleam@list:map(
Indexed,
fun(Pair) ->
decode_expr(
erlang:element(1, Pair),
erlang:element(2, Pair),
0,
Depth_var
)
end
),
Body = <<<<<<<<"{"/utf8, Bare/binary>>/binary, ", "/utf8>>/binary,
(gleam@string:join(Body_terms, <<", "/utf8>>))/binary>>/binary,
"}"/utf8>>,
<<<<<<<<<<<<<<"decode_"/utf8, Type_atom/binary>>/binary, "("/utf8>>/binary,
Pattern/binary>>/binary,
", "/utf8>>/binary,
Depth_var/binary>>/binary,
") ->\n "/utf8>>/binary,
Body/binary>>
end.
-file("src/libero/etf/codegen_erl.gleam", 320).
?DOC(
" Render the Erlang expression that encodes an in-scope BEAM value\n"
" (bound to `expr`) into wire shape. `depth` is used to mint fresh\n"
" variable names for nested containers so generated source has no\n"
" shadow warnings.\n"
).
-spec encode_expr(libero@field_type:field_type(), binary(), integer()) -> binary().
encode_expr(Field_type, Expr, Depth) ->
Inner_var = fresh_var(Depth),
case Field_type of
int_field ->
Expr;
string_field ->
Expr;
bool_field ->
Expr;
bit_array_field ->
Expr;
nil_field ->
Expr;
float_field ->
<<<<"encode_float("/utf8, Expr/binary>>/binary, ")"/utf8>>;
{user_type, Module_path, Type_name, _} ->
Qual = libero@walker:qualified_atom_name(Module_path, Type_name),
<<<<<<<<"encode_"/utf8, Qual/binary>>/binary, "("/utf8>>/binary,
Expr/binary>>/binary,
")"/utf8>>;
{list_of, Element} ->
Inner = encode_expr(Element, Inner_var, Depth + 1),
case Inner =:= Inner_var of
true ->
Expr;
false ->
<<<<<<<<<<<<"["/utf8, Inner/binary>>/binary, " || "/utf8>>/binary,
Inner_var/binary>>/binary,
" <- "/utf8>>/binary,
Expr/binary>>/binary,
"]"/utf8>>
end;
{option_of, Inner@1} ->
Body = encode_expr(Inner@1, Inner_var, Depth + 1),
case Body =:= Inner_var of
true ->
Expr;
false ->
<<<<<<<<<<<<"case "/utf8, Expr/binary>>/binary,
" of {some, "/utf8>>/binary,
Inner_var/binary>>/binary,
"} -> {some, "/utf8>>/binary,
Body/binary>>/binary,
"}; none -> none end"/utf8>>
end;
{result_of, Ok, Err} ->
Err_var = <<"_E"/utf8, (erlang:integer_to_binary(Depth))/binary>>,
Ok_body = encode_expr(Ok, Inner_var, Depth + 1),
Err_body = encode_expr(Err, Err_var, Depth + 1),
case (Ok_body =:= Inner_var) andalso (Err_body =:= Err_var) of
true ->
Expr;
false ->
<<<<<<<<<<<<<<<<<<<<"case "/utf8, Expr/binary>>/binary,
" of {ok, "/utf8>>/binary,
Inner_var/binary>>/binary,
"} -> {ok, "/utf8>>/binary,
Ok_body/binary>>/binary,
"}; {error, "/utf8>>/binary,
Err_var/binary>>/binary,
"} -> {error, "/utf8>>/binary,
Err_body/binary>>/binary,
"} end"/utf8>>
end;
{dict_of, _, Value} ->
Body@1 = encode_expr(Value, Inner_var, Depth + 1),
case Body@1 =:= Inner_var of
true ->
Expr;
false ->
<<<<<<<<<<<<"maps:map(fun(_K, "/utf8, Inner_var/binary>>/binary,
") -> "/utf8>>/binary,
Body@1/binary>>/binary,
" end, "/utf8>>/binary,
Expr/binary>>/binary,
")"/utf8>>
end;
{tuple_of, Elements} ->
Indexed = gleam@list:index_map(
Elements,
fun(Element@1, Index) ->
{Element@1,
<<<<<<"_T"/utf8,
(erlang:integer_to_binary(Depth))/binary>>/binary,
"_"/utf8>>/binary,
(erlang:integer_to_binary(Index))/binary>>}
end
),
Bind_vars = gleam@list:map(
Indexed,
fun(Pair) -> erlang:element(2, Pair) end
),
Body_terms = gleam@list:map(
Indexed,
fun(Pair@1) ->
encode_expr(
erlang:element(1, Pair@1),
erlang:element(2, Pair@1),
Depth + 1
)
end
),
case Body_terms =:= Bind_vars of
true ->
Expr;
false ->
<<<<<<<<<<<<"case "/utf8, Expr/binary>>/binary,
" of {"/utf8>>/binary,
(gleam@string:join(Bind_vars, <<", "/utf8>>))/binary>>/binary,
"} -> {"/utf8>>/binary,
(gleam@string:join(Body_terms, <<", "/utf8>>))/binary>>/binary,
"} end"/utf8>>
end;
{type_var, Name} ->
<<<<"erlang:error({wire_typevar_not_supported, <<\""/utf8,
Name/binary>>/binary,
"\">>})"/utf8>>
end.
-file("src/libero/etf/codegen_erl.gleam", 219).
-spec emit_encode_clause(libero@walker:discovered_variant(), binary()) -> binary().
emit_encode_clause(V, Type_atom) ->
Bare = libero@walker:to_snake_case(erlang:element(3, V)),
Hash = wire_hash_for_variant(V),
case erlang:element(7, V) of
[] ->
<<<<<<<<<<<<"encode_"/utf8, Type_atom/binary>>/binary, "("/utf8>>/binary,
Bare/binary>>/binary,
") ->\n '"/utf8>>/binary,
Hash/binary>>/binary,
"'"/utf8>>;
Fields ->
Indexed = gleam@list:index_map(
Fields,
fun(Ft, I) -> {Ft, top_var(I)} end
),
Pattern_vars = gleam@list:map(
Indexed,
fun(P) -> erlang:element(2, P) end
),
Pattern = <<<<<<<<"{"/utf8, Bare/binary>>/binary, ", "/utf8>>/binary,
(gleam@string:join(Pattern_vars, <<", "/utf8>>))/binary>>/binary,
"}"/utf8>>,
Body_terms = gleam@list:map(
Indexed,
fun(Pair) ->
encode_expr(
erlang:element(1, Pair),
erlang:element(2, Pair),
0
)
end
),
Body = <<<<<<<<"{'"/utf8, Hash/binary>>/binary, "', "/utf8>>/binary,
(gleam@string:join(Body_terms, <<", "/utf8>>))/binary>>/binary,
"}"/utf8>>,
<<<<<<<<<<"encode_"/utf8, Type_atom/binary>>/binary, "("/utf8>>/binary,
Pattern/binary>>/binary,
") ->\n "/utf8>>/binary,
Body/binary>>
end.
-file("src/libero/etf/codegen_erl.gleam", 204).
-spec emit_type_transformers(libero@walker:discovered_type()) -> binary().
emit_type_transformers(Dt) ->
Type_atom = type_function_atom(Dt),
Encode_clauses = gleam@list:map(
erlang:element(5, Dt),
fun(V) -> emit_encode_clause(V, Type_atom) end
),
Decode_clauses = gleam@list:map(
erlang:element(5, Dt),
fun(V@1) -> emit_decode_clause(V@1, Type_atom) end
),
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"%% Type: "/utf8,
(erlang:element(
2,
Dt
))/binary>>/binary,
"."/utf8>>/binary,
(erlang:element(
3,
Dt
))/binary>>/binary,
"
"/utf8>>/binary,
(gleam@string:join(
Encode_clauses,
<<";\n"/utf8>>
))/binary>>/binary,
".
"/utf8>>/binary,
"decode_"/utf8>>/binary,
Type_atom/binary>>/binary,
"(Value) -> decode_"/utf8>>/binary,
Type_atom/binary>>/binary,
"(Value, 0).\n\n"/utf8>>/binary,
"decode_"/utf8>>/binary,
Type_atom/binary>>/binary,
"(_Value, Depth) when Depth >= 512 ->\n error({wire_depth_exceeded, Depth});\n"/utf8>>/binary,
(gleam@string:join(Decode_clauses, <<";\n"/utf8>>))/binary>>/binary,
"."/utf8>>.
-file("src/libero/etf/codegen_erl.gleam", 102).
-spec build_exports(list(libero@walker:discovered_type())) -> binary().
build_exports(Discovered) ->
Type_exports = gleam@list:flat_map(
Discovered,
fun(Dt) ->
Type_atom = type_function_atom(Dt),
[<<<<"encode_"/utf8, Type_atom/binary>>/binary, "/1"/utf8>>,
<<<<"decode_"/utf8, Type_atom/binary>>/binary, "/1"/utf8>>]
end
),
Common = [<<"encode_term/1"/utf8>>,
<<"decode_term/1"/utf8>>,
<<"encode_float/1"/utf8>>],
_pipe = lists:append(Type_exports, Common),
_pipe@1 = gleam@list:map(_pipe, fun(E) -> <<" "/utf8, E/binary>> end),
gleam@string:join(_pipe@1, <<",\n"/utf8>>).
-file("src/libero/etf/codegen_erl.gleam", 88).
?DOC(
" Project DiscoveredType+Variant pairs into the minimal `Constructor`\n"
" shape used by `wire_identity` (module path, name, fields). Used by\n"
" `generate` for the wire-safety and uniqueness pre-checks.\n"
).
-spec constructors_from_discovered(list(libero@walker:discovered_type())) -> list(libero@wire_identity:constructor()).
constructors_from_discovered(Discovered) ->
gleam@list:flat_map(
Discovered,
fun(T) ->
gleam@list:map(
erlang:element(5, T),
fun(V) ->
{constructor,
erlang:element(2, V),
erlang:element(3, V),
erlang:element(7, V)}
end
)
end
).
-file("src/libero/etf/codegen_erl.gleam", 41).
?DOC(
" Generate the source of a `<consumer>_wire.erl` module containing\n"
" per-type encode/decode parent transformers for every discovered\n"
" user type.\n"
"\n"
" Returns `Error(GenError)` on the first wire-safety violation found\n"
" (unsupported Dict key, unresolved TypeVar) or hash collision. The\n"
" emitter assumes its inputs are wire-safe; rejecting up-front keeps\n"
" the output codegen logic narrow and free of runtime fallbacks.\n"
).
-spec generate(binary(), list(libero@walker:discovered_type())) -> {ok,
binary()} |
{error, libero@gen_error:gen_error()}.
generate(Module_name, Discovered) ->
Constructors = constructors_from_discovered(Discovered),
gleam@result:'try'(
libero@wire_identity:check_wire_safety(Constructors),
fun(_) ->
gleam@result:'try'(
libero@wire_identity:check_uniqueness(Constructors),
fun(_) ->
Exports = build_exports(Discovered),
Transformers = begin
_pipe = Discovered,
_pipe@1 = gleam@list:map(
_pipe,
fun emit_type_transformers/1
),
gleam@string:join(_pipe@1, <<"\n\n"/utf8>>)
end,
Encode_term = emit_encode_term(Discovered),
Decode_term = emit_decode_term(Discovered),
Body = begin
_pipe@2 = [float_helper_source(),
Transformers,
Encode_term,
Decode_term],
_pipe@3 = gleam@list:filter(
_pipe@2,
fun(Section) -> Section /= <<""/utf8>> end
),
gleam@string:join(_pipe@3, <<"\n\n"/utf8>>)
end,
{ok,
<<<<<<<<<<<<"%% Code generated by libero. DO NOT EDIT.
%%
%% Per-type wire-format encode/decode transformers. Translates between
%% BEAM-shape (bare atom constructor tags) and wire-shape (10-char
%% hex hash atom tags computed at codegen time by libero/wire_identity).
%%
%% encode_<T>/1 takes a BEAM tuple and returns the wire-shape tuple.
%% decode_<T>/1 is the inverse. Function names are qualified by
%% module path so types with the same name in different Gleam modules
%% do not collide in this Erlang module's function table.
-module("/utf8,
Module_name/binary>>/binary,
").
-export([
"/utf8>>/binary,
Exports/binary>>/binary,
"
]).
"/utf8>>/binary,
Body/binary>>/binary,
"
"/utf8>>}
end
)
end
).