structured_io v1.5.0 StructuredIO View Source

A process for performing I/O of structured data, such as markup or binary-encoded data.

Encoding

The process operates in either binary mode or Unicode mode (see start/2 and start_link/2). When in binary mode, the result of a read operation is a binary, regardless of whether the data read is String.valid?/1. In Unicode mode, the result of a read operation is an error/0 if the data read is not properly encoded Unicode data.

Link to this section Summary

Types

A number of bytes or graphemes in a measured data element

An error result

A binary value which marks the beginning of an enclosed data element

The portion of a binary value matched in a read operation

A mode of operation for the process: either binary or Unicode

A function around which read_complex/3 behavior will be wrapped

A binary value which marks the end of an enclosed or terminated data element

Functions

Returns a specification to start this module under a supervisor

Returns a value that can be passed to Enum.into/2 or Enum.into/3 for writing data to the specified structured_io

Returns a value that can be passed to functions such as Enum.map/2 for reading data elements from the specified structured_io, using the specified StructuredIO function, and the specified left and/or right/operation

Gets the mode of the specified structured_io

Reads data from the specified structured_io in the specified quantity, or beginning with the specified binary value. In binary mode, a numeric count_or_match denotes a number of bytes; in Unicode mode, a numeric count_or_match denotes a number of graphemes

Reads data from the specified structured_io beginning with the specified left and ending with the occurrence of the specified right that corresponds to it, inclusive

Reads data from the specified structured_io beginning with the specified left and ending with the first occurrence of the specified right, inclusive

Reads data from the specified structured_io beginning with the specified left and ending with the occurrence of the specified right that corresponds to it, exclusive

Reads data from the specified structured_io beginning with the specified left and ending with the first occurrence of the specified right, exclusive

Invokes the specified operation, changing the state of the specified structured_io only if the operation is successful. Success is indicated when the operation returns {:ok, term}, in which case only the term is returned

Reads data from the specified structured_io if and until the specified right is encountered, including right

Reads data from the specified structured_io if and until the specified right is encountered, excluding right

Starts a StructuredIO process without links (outside a supervision tree) with the specified mode and options

Starts a StructuredIO process linked to the current process with the specified mode and options

Stops the specified structured_io process

Writes the specified data to the specified structured_io

Link to this section Types

A number of bytes or graphemes in a measured data element.

Link to this type error() View Source
error() :: {:error, atom() | binary()}

An error result.

A binary value which marks the beginning of an enclosed data element.

The portion of a binary value matched in a read operation.

Link to this type mode() View Source
mode() :: :binary | :unicode

A mode of operation for the process: either binary or Unicode.

Link to this type operation() View Source
operation() :: (GenServer.server() -> {:ok, any()} | any())

A function around which read_complex/3 behavior will be wrapped.

A binary value which marks the end of an enclosed or terminated data element.

Link to this section Functions

Returns a specification to start this module under a supervisor.

See Supervisor.

Returns a value that can be passed to Enum.into/2 or Enum.into/3 for writing data to the specified structured_io.

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""
iex> collector = StructuredIO.collect(structured_io)
iex> ["<elem>foo</elem>",
...>  "<elem>bar</elem>",
...>  "<elem>baz</elem>"]
iex> |> Enum.into(collector)
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
"foo"
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
"bar"
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
"baz"
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""
Link to this function enumerate_with(structured_io, function, left, right) View Source
enumerate_with(
  GenServer.server(),
  :read_across
  | :read_across_ignoring_overlap
  | :read_between
  | :read_between_ignoring_overlap,
  left(),
  right()
) :: StructuredIO.Enumerator.t()

Returns a value that can be passed to functions such as Enum.map/2 for reading data elements from the specified structured_io, using the specified StructuredIO function, and the specified left and/or right/operation.

Note that enumeration is not a purely functional operation; it consumes data elements from the underlying StructuredIO process.

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>foo</elem>"
:ok
iex> StructuredIO.write structured_io,
...>                    "<elem>bar</elem>"
:ok
iex> StructuredIO.write structured_io,
...>                    "<elem>baz</elem>"
:ok
iex> structured_io
...> |> StructuredIO.enumerate_with(:read_between,
...>                                "<elem>",
...>                                "</elem>")
...> |> StructuredIO.Enumerator.timeout(60_000)
...> |> Enum.map(&String.upcase/1)
["FOO",
 "BAR",
 "BAZ"]
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "foo<br/>"
:ok
iex> StructuredIO.write structured_io,
...>                    "bar<br/>"
:ok
iex> StructuredIO.write structured_io,
...>                    "baz<br/>"
:ok
iex> structured_io
...> |> StructuredIO.enumerate_with(:read_through,
...>                                "<br/>")
...> |> StructuredIO.Enumerator.timeout(:infinity)
...> |> Enum.map(&String.upcase/1)
["FOO<BR/>",
 "BAR<BR/>",
 "BAZ<BR/>"]
iex> StructuredIO.read_through structured_io,
...>                           "<br />"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> read_tag_length_value = fn s ->
...>   with tag
...>          when not (tag in ["", <<0>>])
...>          <- StructuredIO.read(s, 1),
...>        <<length::size(8)>>
...>          <- StructuredIO.read(s, 1),
...>        value
...>          when (length == 0) or
...>               (value != "")
...>          <- StructuredIO.read(s, length) do
...>     {:ok,
...>      %{tag: tag,
...>        length: length,
...>        value: value}}
...>   end
...> end
iex> StructuredIO.write structured_io,
...>                    <<111, 0, 222, 3, "foo">>
:ok
iex> structured_io
...> |> StructuredIO.enumerate_with(:read_complex,
...>                                read_tag_length_value)
...> |> Enum.into([])
[%{tag: <<111>>,
   length: 0,
   value: ""},
 %{tag: <<222>>,
   length: 3,
   value: "foo"}]
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
""

To override the default per-element timeout of a read* function, call StructuredIO.Enumerator.timeout/2 as shown above.

Gets the mode of the specified structured_io.

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.mode structured_io
:binary

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.mode structured_io
:unicode
Link to this function read(structured_io, count_or_match, timeout \\ 5000) View Source
read(GenServer.server(), count() | match(), timeout()) :: match() | error()

Reads data from the specified structured_io in the specified quantity, or beginning with the specified binary value. In binary mode, a numeric count_or_match denotes a number of bytes; in Unicode mode, a numeric count_or_match denotes a number of graphemes.

If the data in the process does not contain at least the expected (quantity of) data, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<23, 45>>
:ok
iex> StructuredIO.read structured_io,
...>                   3
""
iex> StructuredIO.write structured_io,
...>                    <<67>>
:ok
iex> StructuredIO.read structured_io,
...>                   3
<<23, 45, 67>>
iex> StructuredIO.read structured_io,
...>                   3
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "\r\nfo"
:ok
iex> StructuredIO.read structured_io,
...>                   4
""
iex> StructuredIO.write structured_io,
...>                    "o"
:ok
iex> StructuredIO.read structured_io,
...>                   4
"\r\nfoo"
iex> StructuredIO.read structured_io,
...>                   4
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "fo"
:ok
iex> StructuredIO.read structured_io,
...>                   "foo"
""
iex> StructuredIO.write structured_io,
...>                    "obar"
:ok
iex> StructuredIO.read structured_io,
...>                   "foo"
"foo"
iex> StructuredIO.read structured_io,
...>                   "foo"
""
iex> StructuredIO.read structured_io,
...>                   "bar"
"bar"
iex> StructuredIO.read structured_io,
...>                   "bar"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read structured_io,
...>                   4
""
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.read structured_io,
...>                   4
"😕"
iex> StructuredIO.read structured_io,
...>                   4
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read structured_io,
...>                   "😕"
""
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.read structured_io,
...>                   "😕"
"😕"
iex> StructuredIO.read structured_io,
...>                   "😕"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read structured_io,
...>                   1
{:error,
 "UnicodeConversionError: incomplete encoding starting at #{inspect fragment1}"}
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.read structured_io,
...>                   1
"😕"
iex> StructuredIO.read structured_io,
...>                   1
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read structured_io,
...>                   "😕"
{:error,
 "UnicodeConversionError: incomplete encoding starting at #{inspect fragment1}"}
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.read structured_io,
...>                   "😕"
"😕"
iex> StructuredIO.read structured_io,
...>                   "😕"
""

See mode/1.

Link to this function read_across(structured_io, left, right, timeout \\ 5000) View Source
read_across(GenServer.server(), left(), right(), timeout()) :: match() | error()

Reads data from the specified structured_io beginning with the specified left and ending with the occurrence of the specified right that corresponds to it, inclusive.

If the data in the process does not both begin with left and contain a corresponding right, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255, 255, 255, 255>>
:ok
iex> StructuredIO.read_across structured_io,
...>                          <<0, 0, 0>>,
...>                          <<255, 255, 255>>
""
iex> StructuredIO.write structured_io,
...>                    <<255, 0, 0, 0, 7, 8, 9, 255, 255, 255>>
:ok
iex> StructuredIO.read_across structured_io,
...>                          <<0, 0, 0>>,
...>                          <<255, 255, 255>>
<<0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255, 255, 255, 255, 255>>
iex> StructuredIO.read_across structured_io,
...>                          <<0, 0, 0>>,
...>                          <<255, 255, 255>>
<<0, 0, 0, 7, 8, 9, 255, 255, 255>>
iex> StructuredIO.read_across structured_io,
...>                          <<0, 0, 0>>,
...>                          <<255, 255, 255>>
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>foo<elem>bar</elem></elem"
:ok
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
""
iex> StructuredIO.write structured_io,
...>                    "><elem>baz</elem>"
:ok
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
"<elem>foo<elem>bar</elem></elem>"
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
"<elem>baz</elem>"
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    "<elem>"
:ok
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
""
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "</elem>"
:ok
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
"<elem>😕</elem>"
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>"
:ok
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
{:error,
 "UnicodeConversionError: incomplete encoding starting at #{inspect fragment1}"}
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "</elem>"
:ok
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
"<elem>😕</elem>"
iex> StructuredIO.read_across structured_io,
...>                          "<elem>",
...>                          "</elem>"
""
Link to this function read_across_ignoring_overlap(structured_io, left, right, timeout \\ 5000) View Source
read_across_ignoring_overlap(GenServer.server(), left(), right(), timeout()) ::
  match() | error()

Reads data from the specified structured_io beginning with the specified left and ending with the first occurrence of the specified right, inclusive.

If the data in the process does not both begin with left and contain right, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255>>
:ok
iex> StructuredIO.read_across_ignoring_overlap structured_io,
...>                                           <<0, 0, 0>>,
...>                                           <<255, 255, 255>>
""
iex> StructuredIO.write structured_io,
...>                    <<255>>
:ok
iex> StructuredIO.read_across_ignoring_overlap structured_io,
...>                                           <<0, 0, 0>>,
...>                                           <<255, 255, 255>>
<<0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255, 255>>

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>foo<elem>bar</elem"
:ok
iex> StructuredIO.read_across_ignoring_overlap structured_io,
...>                                           "<elem>",
...>                                           "</elem>"
""
iex> StructuredIO.write structured_io,
...>                    ">"
:ok
iex> StructuredIO.read_across_ignoring_overlap structured_io,
...>                                           "<elem>",
...>                                           "</elem>"
"<elem>foo<elem>bar</elem>"
Link to this function read_between(structured_io, left, right, timeout \\ 5000) View Source
read_between(GenServer.server(), left(), right(), timeout()) ::
  match() | error()

Reads data from the specified structured_io beginning with the specified left and ending with the occurrence of the specified right that corresponds to it, exclusive.

If the data in the process does not both begin with left and contain a corresponding right, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255, 255, 255, 255>>
:ok
iex> StructuredIO.read_between structured_io,
...>                           <<0, 0, 0>>,
...>                           <<255, 255, 255>>
""
iex> StructuredIO.write structured_io,
...>                    <<255>>
:ok
iex> StructuredIO.read_between structured_io,
...>                           <<0, 0, 0>>,
...>                           <<255, 255, 255>>
<<1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255, 255>>

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>foo<elem>bar</elem></elem"
:ok
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""
iex> StructuredIO.write structured_io,
...>                    ">"
:ok
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
"foo<elem>bar</elem>"

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    "<elem>"
:ok
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "</elem>"
:ok
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
"😕"
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>"
:ok
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
{:error,
 "UnicodeConversionError: incomplete encoding starting at #{inspect fragment1}"}
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "</elem>"
:ok
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
"😕"
iex> StructuredIO.read_between structured_io,
...>                           "<elem>",
...>                           "</elem>"
""
Link to this function read_between_ignoring_overlap(structured_io, left, right, timeout \\ 5000) View Source
read_between_ignoring_overlap(GenServer.server(), left(), right(), timeout()) ::
  match() | error()

Reads data from the specified structured_io beginning with the specified left and ending with the first occurrence of the specified right, exclusive.

If the data in the process does not both begin with left and contain right, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 255, 255>>
:ok
iex> StructuredIO.read_between_ignoring_overlap structured_io,
...>                                            <<0, 0, 0>>,
...>                                            <<255, 255, 255>>
""
iex> StructuredIO.write structured_io,
...>                    <<255>>
:ok
iex> StructuredIO.read_between_ignoring_overlap structured_io,
...>                                            <<0, 0, 0>>,
...>                                            <<255, 255, 255>>
<<1, 2, 3, 0, 0, 0, 4, 5, 6>>

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "<elem>foo<elem>bar</elem"
:ok
iex> StructuredIO.read_between_ignoring_overlap structured_io,
...>                                            "<elem>",
...>                                            "</elem>"
""
iex> StructuredIO.write structured_io,
...>                    ">"
:ok
iex> StructuredIO.read_between_ignoring_overlap structured_io,
...>                                            "<elem>",
...>                                            "</elem>"
"foo<elem>bar"
Link to this function read_complex(structured_io, operation, timeout \\ 5000) View Source
read_complex(GenServer.server(), operation(), timeout()) :: any()

Invokes the specified operation, changing the state of the specified structured_io only if the operation is successful. Success is indicated when the operation returns {:ok, term}, in which case only the term is returned.

Note: Within the operation, you must not send messages to the structured_io. Send messages instead to the GenServer.server/0 which is an argument to the operation.

Examples

In the following example, a Tag-Length-Value data element is composed of:

  • A fixed-length Tag expression between <<1>> and <<255>> (one byte)
  • A fixed-length Length expression between 0 and 255 (one byte)
  • A variable-length Value expression whose length is the Length

Following the convention of built-in functions such as read_across/4, if the whole element is not present then the result of the operation is an empty binary ("").

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> read_tag_length_value = fn s ->
...>   with tag
...>          when not (tag in ["", <<0>>])
...>          <- StructuredIO.read(s, 1),
...>        <<length::size(8)>>
...>          <- StructuredIO.read(s, 1),
...>        value
...>          when (length == 0) or
...>               (value != "")
...>          <- StructuredIO.read(s, length) do
...>     {:ok,
...>      %{tag: tag,
...>        length: length,
...>        value: value}}
...>   end
...> end
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
""
iex> StructuredIO.write structured_io,
...>                    <<111>>
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
""
iex> StructuredIO.write structured_io,
...>                    0
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
%{tag: <<111>>,
  length: 0,
  value: ""}
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
""
iex> StructuredIO.write structured_io,
...>                    <<222>>
iex> StructuredIO.write structured_io,
...>                    byte_size("foo")
iex> StructuredIO.write structured_io,
...>                    "foo"
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
%{tag: <<222>>,
  length: 3,
  value: "foo"}
iex> StructuredIO.read_complex structured_io,
...>                           read_tag_length_value
""
Link to this function read_through(structured_io, right, timeout \\ 5000) View Source
read_through(GenServer.server(), right(), timeout()) :: match() | error()

Reads data from the specified structured_io if and until the specified right is encountered, including right.

If right is not encountered, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<1, 2, 3, 255, 255>>
:ok
iex> StructuredIO.read_through structured_io,
...>                           <<255, 255, 255>>
""
iex> StructuredIO.write structured_io,
...>                    <<255, 4, 5, 6, 255, 255, 255>>
:ok
iex> StructuredIO.read_through structured_io,
...>                           <<255, 255, 255>>
<<1, 2, 3, 255, 255, 255>>
iex> StructuredIO.read_through structured_io,
...>                           <<255, 255, 255>>
<<4, 5, 6, 255, 255, 255>>
iex> StructuredIO.read_through structured_io,
...>                           <<255, 255, 255>>
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "foo<br/"
:ok
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
""
iex> StructuredIO.write structured_io,
...>                    ">bar<br/>"
:ok
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
"foo<br/>"
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
"bar<br/>"
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
""
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "<br/>"
:ok
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
"😕<br/>"
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
{:error,
 "UnicodeConversionError: incomplete encoding starting at #{inspect fragment1}"}
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "<br/>"
:ok
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
"😕<br/>"
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
""
Link to this function read_to(structured_io, right, timeout \\ 5000) View Source
read_to(GenServer.server(), right(), timeout()) :: match() | error()

Reads data from the specified structured_io if and until the specified right is encountered, excluding right.

If right is not encountered, the result is an empty binary ("").

Examples

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> StructuredIO.write structured_io,
...>                    <<1, 2, 3, 255, 255>>
:ok
iex> StructuredIO.read_to structured_io,
...>                      <<255, 255, 255>>
""
iex> StructuredIO.write structured_io,
...>                    <<255, 4, 5, 6, 255, 255, 255>>
:ok
iex> StructuredIO.read_to structured_io,
...>                      <<255, 255, 255>>
<<1, 2, 3>>
iex> StructuredIO.read_through structured_io,
...>                           <<255, 255, 255>>
<<255, 255, 255>>
iex> StructuredIO.read_to structured_io,
...>                      <<255, 255, 255>>
<<4, 5, 6>>
iex> StructuredIO.read_to structured_io,
...>                      <<255, 255, 255>>
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> StructuredIO.write structured_io,
...>                    "foo<br/"
:ok
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
""
iex> StructuredIO.write structured_io,
...>                    ">bar<br/>"
:ok
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
"foo"
iex> StructuredIO.read_through structured_io,
...>                           "<br/>"
"<br/>"
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
"bar"
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:binary)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
""
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "<br/>"
:ok
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
"😕"
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
""

iex> {:ok,
...>  structured_io} = StructuredIO.start_link(:unicode)
iex> <<fragment1::binary-size(3), fragment2::binary>> = "😕"
iex> StructuredIO.write structured_io,
...>                    fragment1
:ok
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
{:error,
 "UnicodeConversionError: incomplete encoding starting at #{inspect fragment1}"}
iex> StructuredIO.write structured_io,
...>                    fragment2
:ok
iex> StructuredIO.write structured_io,
...>                    "<br/>"
:ok
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
"😕"
iex> StructuredIO.read_to structured_io,
...>                      "<br/>"
""

Starts a StructuredIO process without links (outside a supervision tree) with the specified mode and options.

Examples

iex> StructuredIO.start :super_pursuit_mode
{:error,
 "invalid mode :super_pursuit_mode"}

See start_link/2.

Link to this function start_link(mode, options \\ []) View Source
start_link(mode(), GenServer.options()) :: GenServer.on_start()

Starts a StructuredIO process linked to the current process with the specified mode and options.

Examples

iex> StructuredIO.start_link :super_pursuit_mode
{:error,
 "invalid mode :super_pursuit_mode"}

See mode/1 and the read* functions for more examples.

Link to this function stop(structured_io, reason \\ :normal, timeout \\ :infinity) View Source
stop(GenServer.server(), term(), timeout()) :: :ok

Stops the specified structured_io process.

Link to this function write(structured_io, data) View Source
write(GenServer.server(), iodata() | IO.chardata() | String.Chars.t()) ::
  :ok | error()

Writes the specified data to the specified structured_io.

No timeout is available because the operation is performed asynchronously.

See the read* functions for examples.