structured_io v0.7.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
StructuredIO.start/2
and StructuredIO.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
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 binary value which marks the end of an enclosed or terminated data element
Functions
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
Invoked when the server is started. start_link/3
or start/3
will
block until it returns
Gets the mode of the specified structured_io
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
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
Synchronously stops the specified structured_io
process
Asynchronously writes the specified data
as a binary to the specified
structured_io
Link to this section Types
An error result.
A binary value which marks the beginning of an enclosed data element.
See StructuredIO.read_across/3
and
StructuredIO.read_between/3
.
The portion of a binary value matched in a read operation.
See StructuredIO.read_across/3
,
StructuredIO.read_between/3
,
StructuredIO.read_through/2
, and StructuredIO.read_to/2
.
A mode of operation for the process: either binary or Unicode.
A binary value which marks the end of an enclosed or terminated data element.
See StructuredIO.read_across/3
,
StructuredIO.read_between/3
,
StructuredIO.read_through/2
, and StructuredIO.read_to/2
.
Link to this section Functions
collect(GenServer.server()) :: StructuredIO.Collector.t()
Returns a value that can be passed to Enum.into/2
or Enum.into/3
for
writing data to the specified structured_io
.
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>"
""
enumerate_with(GenServer.server(), :read_through | :read_to, right()) :: StructuredIO.Enumerator.t()
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
.
Note that enumeration is not a purely functional operation; it consumes data
elements from the underlying StructuredIO
process.
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>")
...> |> 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/>")
...> |> Enum.map(&String.upcase/1)
["FOO<BR/>",
"BAR<BR/>",
"BAZ<BR/>"]
iex> StructuredIO.read_through structured_io,
...> "<br />"
""
Invoked when the server is started. start_link/3
or start/3
will
block until it returns.
args
is the argument term (second argument) passed to start_link/3
.
Returning {:ok, state}
will cause start_link/3
to return
{:ok, pid}
and the process to enter its loop.
Returning {:ok, state, timeout}
is similar to {:ok, state}
except handle_info(:timeout, state)
will be called after timeout
milliseconds if no messages are received within the timeout.
Returning {:ok, state, :hibernate}
is similar to
{:ok, state}
except the process is hibernated before entering the loop. See
c:handle_call/3
for more information on hibernation.
Returning :ignore
will cause start_link/3
to return :ignore
and the
process will exit normally without entering the loop or calling c:terminate/2
.
If used when part of a supervision tree the parent supervisor will not fail
to start nor immediately try to restart the GenServer
. The remainder of the
supervision tree will be (re)started and so the GenServer
should not be
required by other processes. It can be started later with
Supervisor.restart_child/2
as the child specification is saved in the parent
supervisor. The main use cases for this are:
- The
GenServer
is disabled by configuration but might be enabled later. - An error occurred and it will be handled by a different mechanism than the
Supervisor
. Likely this approach involves callingSupervisor.restart_child/2
after a delay to attempt a restart.
Returning {:stop, reason}
will cause start_link/3
to return
{:error, reason}
and the process to exit with reason reason
without
entering the loop or calling c:terminate/2
.
Callback implementation for GenServer.init/1
.
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
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.
When the region bounded by the first occurrences of left
and right
overlaps other such regions, the result is the union of them. If data
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>"
""
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 data
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>"
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 data
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>"
""
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 data
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"
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/>"
""
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/>"
""
start(mode(), GenServer.options()) :: GenServer.on_start()
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"}
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 StructuredIO.mode/1
, StructuredIO.read_across/3
,
StructuredIO.read_between/3
,
StructuredIO.read_through/2
, and StructuredIO.read_to/2
for more examples.
stop(GenServer.server(), term(), timeout()) :: :ok
Synchronously stops the specified structured_io
process.
write(GenServer.server(), iodata() | IO.chardata() | String.Chars.t()) :: :ok | error()
Asynchronously writes the specified data
as a binary to the specified
structured_io
.
See StructuredIO.read_across/3
,
StructuredIO.read_between/3
,
StructuredIO.read_through/2
, and StructuredIO.read_to/2
for examples.