Rusult v1.1.0 Rusult View Source

Result struct based on the Rust Result object.

>> Rust Result << -> Rusult

Implemented Rust Result stable functions (1.46):

Extra functions:

Implemented Rust Result unstable functions (1.46):

  • contains ❌
  • contains_err ❌
  • flatten ❌
  • into_ok ❌

Examples

iex> {:ok, 123} |> Rusult.from() |> Rusult.unwrap!()
123
iex> {:ok, 1, 2}  
...> |> Rusult.from()
...> |> Rusult.and_then(fn {a, b} -> Rusult.ok(a + b) end)
...> |> Rusult.to_tuple()
{:ok, 3}
iex> defmodule MyModule do
...>     def transform_value(%Rusult{ok?: true}) do
...>         {:ok, 123}
...>     end
...>     def transform_value(%Rusult{error?: true}) do
...>         {:error, :found_error}
...>     end
...> end
...>
...> "ERROR!"
...> |> Rusult.error()
...> |> MyModule.transform_value()
...> |> Rusult.from()
...> |> Rusult.expect_err!("this is ok?")
:found_error

Use your own Rusult module.

iex> defmodule MyRusult do
...>     @type t :: %__MODULE__{error: binary, ok: map, error?: boolean, ok?: boolean}
...>     @enforce_keys [:error?, :ok?]
...>     defstruct [:error, :ok, :error?, :ok?] 
...>
...>     def from(%Rusult{error: _error, ok: ok, error?: false, ok?: true}) do
...>        from(ok)
...>     end
...>     
...>     def from(%Rusult{error: error, ok: _ok, error?: true, ok?: false}) do
...>        %MyRusult{ok?: false, error?: true, error: error}
...>     end
...>
...>     def from(%MyRusult{} = my_result) do
...>        my_result
...>     end
...>     
...>     def from(data) when is_map(data) do
...>        %MyRusult{ok?: true, error?: false, ok: data}
...>     end
...>
...>     def from(_data) do
...>        %MyRusult{ok?: false, error?: true, error: "invalid data"}
...>     end
...> end
iex> %{data: [1,2,3,4]}
...> |> MyRusult.from()
...> |> Rusult.map(fn %{data: data} -> %{data: Enum.sum(data)} end)
...> |> MyRusult.from()
...> |> Map.from_struct()
%{ok?: true, error?: false, ok: %{data: 10}, error: nil}
iex> "testing"
...> |> MyRusult.from()
...> |> Rusult.map(fn %{data: data} -> Enum.sum(data) end)
...> |> MyRusult.from()
...> |> Map.from_struct()
%{ok?: false, error?: true, error: "invalid data", ok: nil}

Link to this section Summary

Functions

Applies the function if the Rusult is :ok

Creates a :error

Return the value if it is a :error, otherwise returns nil

Return the value if it is a :ok, Raises on :error, with the supplied message.

Return the value if it is a :error, Raises on :ok, with the supplied message.

Create Rusult based on the input

If :error returns the first argument otherwise return the second argument

If :ok returns the first argument otherwise return the second argument

Applies the function if the Rusult is :ok and wraps the output in an :ok

Applies the function if the Rusult is :error and wraps the output in an :error

Applies the function if the Rusult is :error and returns the output of the function. If it is an :ok return the default.

Applies the function if the Rusult is :ok and returns the output of the function. If it is an :error return the default.

Applies the first function if the Rusult is :error and returns the output of the function. Applies the second function if the Rusult is :ok and returns the output of the function.

Creates a :ok

Return the value if it is a :ok, otherwise returns nil

Applies the function if the Rusult is :error

Convert a Rusult back to a elixir error tuple.

Return the value if it is a :ok, Raises on :error.

Return the value if it is a :error, Raises on :ok.

Return the value if it is a :error, otherwise return other

Return the value if it is a :error, otherwise calculate the given function with the ok as its input.

Return the value if it is a :ok, otherwise return other

Return the value if it is a :ok, otherwise calculate the given function with the error as its input.

Alias for from/1

Link to this section Types

Specs

default() :: any()

Specs

function_out() :: any()

Specs

rusult_struct() :: %atom(){
  error: any(),
  ok: any(),
  error?: boolean(),
  ok?: boolean()
}

Specs

t() :: %Rusult{error: any(), error?: boolean(), ok: any(), ok?: boolean()}

Link to this section Functions

Specs

and_then(rusult_struct(), (any() -> function_out())) ::
  function_out() | rusult_struct()

Applies the function if the Rusult is :ok

iex> 5
...> |> Rusult.ok()
...> |> Rusult.and_then(fn x -> Rusult.ok(x * 2) end)
...> |> Rusult.and_then(fn x -> Rusult.ok(x + 1) end)
Rusult.ok(11)

iex> 5
...> |> Rusult.ok()
...> |> Rusult.and_then(fn x -> Rusult.ok(x * 2) end)
...> |> Rusult.and_then(fn _x -> Rusult.error("failed") end)
Rusult.error("failed")

iex> 5
...> |> Rusult.ok()
...> |> Rusult.and_then(fn _x -> Rusult.error("failed") end)
...> |> Rusult.and_then(fn x -> Rusult.ok(x + 1) end)
Rusult.error("failed")

iex> 5
...> |> Rusult.ok()
...> |> Rusult.and_then(fn _x -> Rusult.error("failed") end)
...> |> Rusult.and_then(fn _x -> Rusult.error("still failed") end)
Rusult.error("failed")

like or_else/2 or map/2

Specs

error(any()) :: rusult_struct()

Creates a :error

iex> Rusult.error(:anything)
%Rusult{error?: true, ok?: false, error: :anything}

Return the value if it is a :error, otherwise returns nil

iex> {1, 2, 3} |> Rusult.error() |> Rusult.error_or_nil()
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.ok() |> Rusult.error_or_nil()
nil
Link to this function

expect!(struct, error_message)

View Source

Specs

expect!(rusult_struct(), binary()) :: any()

Return the value if it is a :ok, Raises on :error, with the supplied message.

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.expect!("bang!")
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.error() |> Rusult.expect!("bang!")
** (RuntimeError) bang!
Link to this function

expect_err!(struct, error_message)

View Source

Specs

expect_err!(rusult_struct(), binary()) :: any()

Return the value if it is a :error, Raises on :ok, with the supplied message.

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.expect_err!("bang!")
** (RuntimeError) bang!
iex> {1, 2, 3} |> Rusult.error() |> Rusult.expect_err!("bang!")
{1, 2, 3}

Specs

from(any()) :: rusult_struct()

Create Rusult based on the input

iex> Rusult.from(:anything)
%Rusult{error?: false, ok?: true, ok: :anything}
iex> Rusult.from(:ok)
%Rusult{error?: false, ok?: true}
iex> Rusult.from({:ok, "success"})
%Rusult{error?: false, ok?: true, ok: "success"}
iex> Rusult.from({:error, "failed"})
%Rusult{error?: true, ok?: false, error: "failed"}

Specs

if_err(rusult_struct(), rusult_struct() | any()) :: rusult_struct() | any()

If :error returns the first argument otherwise return the second argument

iex> a = Rusult.ok([1, 2, 3, 4])
iex> b = Rusult.ok(:something)
iex> Rusult.if_err(a, b)
Rusult.ok(:something)

iex> a = Rusult.error(:error)
iex> b = Rusult.ok(:something)
iex> Rusult.if_err(a, b)
Rusult.error(:error)

It is similar to using just an if statement like:

iex> a = Rusult.error(:error)
iex> b = Rusult.ok(:something)
iex> if a.error? do
...>     a
...> else
...>     b
...> end
Rusult.error(:error)

Specs

if_ok(rusult_struct(), rusult_struct() | any()) :: rusult_struct() | any()

If :ok returns the first argument otherwise return the second argument

iex> a = Rusult.ok([1, 2, 3, 4])
iex> b = Rusult.ok(:something)
iex> Rusult.if_ok(a, b)
Rusult.ok([1, 2, 3, 4])

iex> a = Rusult.error(:error)
iex> b = Rusult.ok(:something)
iex> Rusult.if_ok(a, b)
Rusult.ok(:something)

It is similar to using just an if statement like:

iex> a = Rusult.ok([1, 2, 3, 4])
iex> b = Rusult.ok(:something)
iex> if a.ok? do
...>     a
...> else
...>     b
...> end
Rusult.ok([1, 2, 3, 4])

Specs

map(rusult_struct(), (any() -> any())) :: rusult_struct()

Applies the function if the Rusult is :ok and wraps the output in an :ok

Because in Elixir you can overload functions map/3 is an alias for map_or/3

iex> [1, 2, 3, 4]
...> |> Rusult.ok()
...> |> Rusult.map(fn x -> Enum.sum(x) end)
...> |> Rusult.map(fn x -> x + 5 end)
Rusult.ok(15)

iex> [1, 2, 3, 4]
...> |> Rusult.error()
...> |> Rusult.map(fn x -> Enum.sum(x) end)
...> |> Rusult.map(fn x -> x + 5 end)
Rusult.error([1, 2, 3, 4])
Link to this function

map(result, default, func)

View Source

Specs

map(rusult_struct(), default(), (any() -> function_out())) ::
  function_out() | default()

Specs

map_err(rusult_struct(), (any() -> any())) :: rusult_struct()

Applies the function if the Rusult is :error and wraps the output in an :error

iex> [1, 2, 3, 4]
...> |> Rusult.error()
...> |> Rusult.map_err(fn x -> Enum.sum(x) end)
...> |> Rusult.map_err(fn x -> x + 5 end)
Rusult.error(15)

iex> [1, 2, 3, 4]
...> |> Rusult.ok()
...> |> Rusult.map_err(fn x -> Enum.sum(x) end)
...> |> Rusult.map_err(fn x -> x + 5 end)
Rusult.ok([1, 2, 3, 4])
Link to this function

map_err_or(result, default, func)

View Source

Specs

map_err_or(rusult_struct(), default(), (any() -> function_out())) ::
  function_out() | default()

Applies the function if the Rusult is :error and returns the output of the function. If it is an :ok return the default.

iex> [1, 2, 3, 4]
...> |> Rusult.error()
...> |> Rusult.map_err_or(120, fn x -> Enum.sum(x) end)
10

iex> [1, 2, 3, 4]
...> |> Rusult.ok()
...> |> Rusult.map_err_or(120, fn x -> Enum.sum(x) end)
120
Link to this function

map_or(result, default, func)

View Source

Specs

map_or(rusult_struct(), default(), (any() -> function_out())) ::
  function_out() | default()

Applies the function if the Rusult is :ok and returns the output of the function. If it is an :error return the default.

iex> [1, 2, 3, 4]
...> |> Rusult.ok()
...> |> Rusult.map_or(120, fn x -> Enum.sum(x) end)
10

iex> [1, 2, 3, 4]
...> |> Rusult.error()
...> |> Rusult.map_or(120, fn x -> Enum.sum(x) end)
120
Link to this function

map_or_else(struct, error_function, ok_function)

View Source

Specs

map_or_else(rusult_struct(), (any() -> default()), (any() -> function_out())) ::
  function_out() | default()

Applies the first function if the Rusult is :error and returns the output of the function. Applies the second function if the Rusult is :ok and returns the output of the function.

iex> [1, 2, 3, 4]
...> |> Rusult.ok()
...> |> Rusult.map_or_else(
...>     fn e -> Enum.concat(e, [15, 20]) end, 
...>     fn x -> Enum.sum(x) end
...> )
10

iex> [1, 2, 3, 4]
...> |> Rusult.error()
...> |> Rusult.map_or_else(
...>     fn e -> Enum.concat(e, [15, 20]) end, 
...>     fn x -> Enum.sum(x) end
...> )
[1, 2, 3, 4, 15, 20]

Specs

ok(any()) :: rusult_struct()

Creates a :ok

iex> Rusult.ok(:anything)
%Rusult{error?: false, ok?: true, ok: :anything}

Return the value if it is a :ok, otherwise returns nil

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.ok_or_nil()
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.error() |> Rusult.ok_or_nil()
nil

Specs

or_else(rusult_struct(), (any() -> function_out())) ::
  function_out() | rusult_struct()

Applies the function if the Rusult is :error

iex> 5
...> |> Rusult.ok()
...> |> Rusult.or_else(fn x -> Rusult.ok(x * 2) end)
...> |> Rusult.or_else(fn x -> Rusult.ok(x + 1) end)
Rusult.ok(5)

iex> 5
...> |> Rusult.error()
...> |> Rusult.or_else(fn x -> Rusult.ok(x * 2) end)
...> |> Rusult.or_else(fn _x -> Rusult.error("failed") end)
Rusult.ok(10)

iex> 5
...> |> Rusult.ok()
...> |> Rusult.or_else(fn _x -> Rusult.error("failed") end)
...> |> Rusult.or_else(fn x -> Rusult.ok(x + 1) end)
Rusult.ok(5)

iex> 5
...> |> Rusult.error()
...> |> Rusult.or_else(fn _x -> Rusult.error("failed") end)
...> |> Rusult.or_else(fn _x -> Rusult.error("still failed") end)
Rusult.error("still failed")

like and_then/2 or map_err/2

Link to this function

to_tuple(result, opts \\ [])

View Source

Specs

to_tuple(Rusult.t(), keyword()) :: tuple()

Convert a Rusult back to a elixir error tuple.

opts:

  • flatten: boolean. If the result contains a tuple, it can be prepended with the :ok or :error. (true) or wrapped with :ok or :error (false)
iex> %{success: 3.1415} |> Rusult.ok() |> Rusult.to_tuple()
{:ok, %{success: 3.1415}}
iex> %{sad: 3} |> Rusult.error() |> Rusult.to_tuple()
{:error, %{sad: 3}}

flatten:

iex> {1, 2, 3} |> Rusult.error() |> Rusult.to_tuple(flatten: true)
{:error, 1, 2, 3}
iex> {1, 2, 3} |> Rusult.ok() |> Rusult.to_tuple(flatten: false)
{:ok, {1, 2, 3}}

Specs

unwrap!(rusult_struct()) :: any()

Return the value if it is a :ok, Raises on :error.

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap!()
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap!()
** (RuntimeError) expected :ok, got {1, 2, 3}

Specs

unwrap_err!(rusult_struct()) :: any()

Return the value if it is a :error, Raises on :ok.

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap_err!()
** (RuntimeError) expected :error, got {1, 2, 3}
iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap_err!()
{1, 2, 3}
Link to this function

unwrap_err_or(struct, other)

View Source

Specs

unwrap_err_or(rusult_struct(), any()) :: any()

Return the value if it is a :error, otherwise return other

iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap_err_or(15)
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap_err_or(15)
15
Link to this function

unwrap_err_or_else(struct, func)

View Source

Specs

unwrap_err_or_else(rusult_struct(), (any() -> any())) :: any()

Return the value if it is a :error, otherwise calculate the given function with the ok as its input.

iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap_err_or_else(&elem(&1, 2))
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap_err_or_else(&elem(&1, 2))
3

This can also be used to calculate something dificult

iex> get_tau = fn _ -> 
...>     # get something
...>     3.14159 * 2
...> end
iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap_err_or_else(get_tau)
6.28318
Link to this function

unwrap_or(struct, other)

View Source

Specs

unwrap_or(rusult_struct(), any()) :: any()

Return the value if it is a :ok, otherwise return other

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap_or(15)
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap_or(15)
15
Link to this function

unwrap_or_else(struct, func)

View Source

Specs

unwrap_or_else(rusult_struct(), (any() -> any())) :: any()

Return the value if it is a :ok, otherwise calculate the given function with the error as its input.

iex> {1, 2, 3} |> Rusult.ok() |> Rusult.unwrap_or_else(&elem(&1, 2))
{1, 2, 3}
iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap_or_else(&elem(&1, 2))
3

This can also be used to calculate something dificult

iex> get_tau = fn _ -> 
...>     # get something
...>     3.14159 * 2
...> end
iex> {1, 2, 3} |> Rusult.error() |> Rusult.unwrap_or_else(get_tau)
6.28318

Alias for from/1

iex> Rusult.wrap(:anything)
%Rusult{error?: false, ok?: true, ok: :anything}