-module(metamon@transform). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/metamon/transform.gleam"). -export([new/2, identity/0, constant/2, then/2, repeat/2, rename/2]). -export_type([transform/1]). -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( " Named, deterministic input transformations. The `name` is surfaced\n" " in failure messages so a metamorphic relation always reports which\n" " transformation produced the follow-up input.\n" ). -type transform(GKZ) :: {transform, binary(), fun((GKZ) -> GKZ)}. -file("src/metamon/transform.gleam", 16). ?DOC(" Construct a transform from a name and a function.\n"). -spec new(binary(), fun((GLA) -> GLA)) -> transform(GLA). new(Name, Apply) -> {transform, Name, Apply}. -file("src/metamon/transform.gleam", 21). ?DOC(" The transform that returns its input unchanged.\n"). -spec identity() -> transform(any()). identity() -> {transform, <<"identity"/utf8>>, fun(Value) -> Value end}. -file("src/metamon/transform.gleam", 28). ?DOC( " A transform that ignores its input and always returns `value`.\n" " Use sparingly — most metamorphic relations want a real\n" " transformation rather than a constant.\n" ). -spec constant(binary(), GLE) -> transform(GLE). constant(Name, Value) -> {transform, Name, fun(_) -> Value end}. -file("src/metamon/transform.gleam", 34). ?DOC( " Sequential composition: `then(t1, t2).apply(x) == t2.apply(t1.apply(x))`.\n" " The composite name is `\" |> \"`.\n" ). -spec then(transform(GLG), transform(GLG)) -> transform(GLG). then(T1, T2) -> {transform, <<<<(erlang:element(2, T1))/binary, " |> "/utf8>>/binary, (erlang:element(2, T2))/binary>>, fun(Value) -> (erlang:element(3, T2))((erlang:element(3, T1))(Value)) end}. -file("src/metamon/transform.gleam", 57). -spec repeat_step(fun((GLO) -> GLO), integer(), GLO) -> GLO. repeat_step(F, Remaining, Value) -> case Remaining =< 0 of true -> Value; false -> repeat_step(F, Remaining - 1, F(Value)) end. -file("src/metamon/transform.gleam", 53). -spec repeat_apply(fun((GLN) -> GLN), integer()) -> fun((GLN) -> GLN). repeat_apply(F, Times) -> fun(Value) -> repeat_step(F, Times, Value) end. -file("src/metamon/transform.gleam", 42). ?DOC( " Apply `t` exactly `n` times. `repeat(t, 0)` is `identity`. Negative\n" " counts are treated as `0`.\n" ). -spec repeat(transform(GLK), integer()) -> transform(GLK). repeat(T, N) -> case N =< 0 of true -> identity(); false -> {transform, <<<<(erlang:element(2, T))/binary, " × "/utf8>>/binary, (erlang:integer_to_binary(N))/binary>>, repeat_apply(erlang:element(3, T), N)} end. -file("src/metamon/transform.gleam", 66). ?DOC( " Override the name of a transform. The behaviour of `apply` is not\n" " changed — only the label that appears in failure reports.\n" ). -spec rename(transform(GLP), binary()) -> transform(GLP). rename(T, Name) -> {transform, Name, erlang:element(3, T)}.