The size of what a built-in function is going to make, worked out before it makes it (D-154).
max_list_length and max_string_length refuse a value when it is finished (Feel.Runtime.Env.settle/3), which is
too late for a function whose result is as large as the product of the sizes of its arguments: string join of
5,000 strings of one byte with a delimiter of 100 KB makes 500 MB before the limit looks at it, and the limits would
allow 100 GB. Such a function works out the size first, counting as it walks its arguments and ending the walk at the
first count over the limit, and refuses with the function that settle/3 uses (Feel.Runtime.Env.check_string_length/2,
check_list_length/2), so the error, the diagnostics in it and its effect on the run are the same as for the
finished value, in either mode and on either backend: the result that is within the limits is the one it always was,
and the one over them is refused with nothing built.
A count that is over a limit is a lower bound of the size of the result, and that is all the error says of it.
Summary
Functions
Ends the run if the string that joins items with delimiter (and has extra more bytes, for a prefix and a suffix)
would be longer than max_string_length; the bytes are added up as the items come, so the walk ends at the first
item that passes the limit, and the string is not made. items are strings and not null.
Ends the run with the error of a list that is longer than max_list_length, for a function that has counted length
items of a list it was going to make. The same as refuse_string/2 is for a string.
Ends the run with the error of a string that is longer than max_string_length, for a function that has found, with
size bytes counted, that the string it was going to make is. size is over the limit, and a call that is not
is a mistake of the caller.
Functions
@spec check_join(Feel.Runtime.Env.t(), [String.t()], String.t(), non_neg_integer()) :: Feel.Runtime.Env.t()
Ends the run if the string that joins items with delimiter (and has extra more bytes, for a prefix and a suffix)
would be longer than max_string_length; the bytes are added up as the items come, so the walk ends at the first
item that passes the limit, and the string is not made. items are strings and not null.
iex> env = Feel.Runtime.Env.new(limits: Feel.Limits.new(max_string_length: 5))
iex> ^env = Feel.Builtin.Size.check_join(env, ["ab", "cd"], "+", 0)
iex> {:error, error} = Feel.Runtime.Env.run(env, fn env -> {Feel.Builtin.Size.check_join(env, ["ab", "cd"], "+", 1), env} end)
iex> {error.kind, hd(error.diagnostics).details}
{:limit, %{limit: :max_string_length}}
@spec refuse_list(Feel.Runtime.Env.t(), non_neg_integer()) :: no_return()
Ends the run with the error of a list that is longer than max_list_length, for a function that has counted length
items of a list it was going to make. The same as refuse_string/2 is for a string.
iex> env = Feel.Runtime.Env.new(limits: Feel.Limits.new(max_list_length: 2))
iex> {:error, error} = Feel.Runtime.Env.run(env, fn env -> {Feel.Builtin.Size.refuse_list(env, 3), env} end)
iex> {error.kind, hd(error.diagnostics).details}
{:limit, %{limit: :max_list_length}}
@spec refuse_string(Feel.Runtime.Env.t(), non_neg_integer()) :: no_return()
Ends the run with the error of a string that is longer than max_string_length, for a function that has found, with
size bytes counted, that the string it was going to make is. size is over the limit, and a call that is not
is a mistake of the caller.
iex> env = Feel.Runtime.Env.new(limits: Feel.Limits.new(max_string_length: 5))
iex> {:error, error} = Feel.Runtime.Env.run(env, fn env -> {Feel.Builtin.Size.refuse_string(env, 6), env} end)
iex> {error.kind, hd(error.diagnostics).details}
{:limit, %{limit: :max_string_length}}