Next: stream.string_writer, Previous: store, Up: Top [Contents]
%--------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%--------------------------------------------------%
% Copyright (C) 2006-2007, 2010 The University of Melbourne.
% Copyright (C) 2014-2023 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%--------------------------------------------------%
%
% File: stream.m.
% Authors: juliensf, maclarty.
% Stability: low
%
% This module provides a family of type classes for defining streams
% in Mercury. It also provides some generic predicates that operate
% on instances of these type classes.
%
%--------------------------------------------------%
%--------------------------------------------------%
:- module stream.
:- interface.
:- import_module bool.
:- import_module char.
:- import_module list.
:- include_module string_writer.
%--------------------------------------------------%
%
% Types used by streams.
%
:- type name == string.
:- type result(Error)
---> ok
; eof
; error(Error).
:- type result(T, Error)
---> ok(T)
; eof
; error(Error).
:- type res(Error)
---> ok
; error(Error).
:- type res(T, Error)
---> ok(T)
; error(Error).
% maybe_partial_res is used when it is possible to return a partial result
% when an error occurs.
%
:- type maybe_partial_res(T, Error)
---> ok(T)
; error(T, Error).
%--------------------------------------------------%
%
% Stream errors.
%
:- typeclass error(Error) where
[
% Convert a stream error into a human-readable format.
% e.g. for use in error messages.
%
func error_message(Error) = string
].
%--------------------------------------------------%
%
% Streams.
%
% A stream consists of a handle type and a state type.
% The state type is threaded through the state operations,
% which update it destructively.
%
:- typeclass stream(Stream, State) <= (Stream -> State) where
[
% Returns a descriptive name for the stream.
% Intended for use in error messages.
%
pred name(Stream::in, name::out, State::di, State::uo) is det
].
%--------------------------------------------------%
%
% Input streams.
%
% An input stream is a source of data.
%
:- typeclass input(Stream, State) <= stream(Stream, State) where [].
% A reader stream is a subclass of a specific input stream that
% can be used to read data of a specific type from that input stream.
% A single input stream can support multiple reader subclasses.
%
:- typeclass reader(Stream, Unit, State, Error)
<= (input(Stream, State), error(Error), (Stream, Unit -> Error)) where
[
% Get the next unit from the given stream.
%
% The get operation should block until the next unit is available,
% or the end of the stream or an error is detected.
%
% If a call to get/4 returns `eof', all further calls to get/4,
% unboxed_get/5 or bulk_get/9 for that stream return `eof'.
%
% If a call to get/4 returns `error(...)', all further calls
% to get/4, unboxed_get/5 or bulk_get/4 for that stream return an error,
% although not necessarily the same one.
%
% XXX We should provide an interface to allow the user to reset the
% error status to try again if an error is transient.
%
pred get(Stream::in, result(Unit, Error)::out,
State::di, State::uo) is det
].
% An unboxed_reader stream is like a reader stream, except that
% it provides an interface that avoids a memory allocation
% when there is no error.
%
:- typeclass unboxed_reader(Stream, Unit, State, Error)
<= (input(Stream, State), error(Error), (Stream, Unit -> Error)) where
[
% Get the next unit from the given stream. On error or eof, return
% an *arbitrary* value of type Unit.
%
% The unboxed_get operation should block until the next unit is available,
% or the end of the stream or an error is detected.
%
% If a call to unboxed_get/5 returns `eof', all further calls to get/4,
% unboxed_get/5 or bulk_get/9 for that stream return `eof'.
%
% If a call to unboxed_get/5 returns `error(...)', all further calls
% to get/4, unboxed_get/5 or bulk_get/4 for that stream return an error,
% although not necessarily the same one.
%
% XXX We should provide an interface to allow the user to reset the
% error status to try again if an error is transient.
%
pred unboxed_get(Stream::in, result(Error)::out, Unit::out,
State::di, State::uo) is det
].
% A bulk_reader stream is a subclass of specific input stream that can
% be used to read multiple items of data of a specific type from that
% input stream into a specified container. For example, binary input
% streams may be able to efficiently read bytes into a bitmap.
% A single input stream can support multiple bulk_reader subclasses.
%
:- typeclass bulk_reader(Stream, Index, Store, State, Error)
<= (input(Stream, State), error(Error), (Stream, Index, Store -> Error))
where
[
% bulk_get(Stream, Index, NumItems, !Store, NumItemsRead, Result, !State):
%
% Read at most NumItems items into the given Store starting at the
% given index, returning the number of items read.
%
% If the read succeeds, Result will be `ok' and NumItemsRead will equal
% NumItems.
%
% On end-of-stream, bulk_get/9 puts as many items as it can into !Store.
% NumItemsRead is less than NumItems, and Result is `ok'.
%
% If an error is detected, bulk_get/9 puts as many items as it can into
% !Store. In such cases, NumItemsRead will be less than NumItems, and
% Result will be `error(Err)'.
%
% Blocks until NumItems items are available or the end of the stream
% is reached or an error is detected.
%
% Throws an exception if Index given is out of range, or if NumItems units
% starting at Index will not fit in !Store.
%
% If a call to bulk_get/4 returns fewer than NumItems items, all further
% calls to get/4, unboxed_get/5 or bulk_get/4 for that stream return no
% items.
%
% If a call to bulk_get/9 returns `error(...)', all further calls to
% get/4, unboxed_get/5 or bulk_get/9 for that stream return an error,
% although not necessarily the same one.
%
pred bulk_get(Stream::in, Index::in, int::in,
Store::bulk_get_di, Store::bulk_get_uo, int::out, res(Error)::out,
State::di, State::uo) is det
].
% XXX These should be di and uo, but with the current state of the mode
% system, an unsafe_promise_unique call would be required at each call
% to bulk_get.
:- mode bulk_get_di == in.
:- mode bulk_get_uo == out.
%--------------------------------------------------%
%
% Output streams.
%
% An output stream is a destination for data.
% Note that unlike input streams, output streams do not include
% an explicit error type. They should handle errors by throwing exceptions.
%
:- typeclass output(Stream, State)
<= stream(Stream, State) where
[
% For buffered output streams, completely write out any data in the buffer.
% For unbuffered streams, this operation is a no-op.
%
pred flush(Stream::in, State::di, State::uo) is det
].
% A writer stream is a subclass of specific output stream that
% can be used to write data of a specific type to that output stream.
% A single output stream can support multiple writer subclasses.
%
:- typeclass writer(Stream, Unit, State)
<= output(Stream, State) where
[
% Write the next unit to the given stream.
% Blocks if the whole unit cannot be written to the stream at the time
% of the call (for example because a buffer is full).
%
pred put(Stream::in, Unit::in, State::di, State::uo) is det
].
%--------------------------------------------------%
%
% Duplex streams.
%
% A duplex stream is a stream that can act as both a source and
% destination of data, i.e. it is a both an input and an output stream.
%
:- typeclass duplex(Stream, State)
<= (input(Stream, State), output(Stream, State)) where
[
].
%--------------------------------------------------%
%
% Putback streams.
%
% A putback stream is an input stream that allows data to be pushed back
% onto the stream. As with reader subclasses, it is possible to define
% multiple putback subclasses for a single input stream.
%
:- typeclass putback(Stream, Unit, State, Error)
<= reader(Stream, Unit, State, Error) where
[
% Un-gets a unit from the specified input stream.
% Only one unit of putback is guaranteed to be successful.
%
pred unget(Stream::in, Unit::in, State::di, State::uo) is det
].
% As above, but guarantees that an unlimited number of units may be pushed
% back onto the stream.
%
:- typeclass unbounded_putback(Stream, Unit, State, Error)
<= putback(Stream, Unit, State, Error) where
[
].
%--------------------------------------------------%
%
% Seekable streams.
%
% whence denotes the base for a seek operation.
% set - seek relative to the start of the file
% cur - seek relative to the current position in the file
% end - seek relative to the end of the file.
%
:- type whence
---> set
; cur
; end.
:- typeclass seekable(Stream, State) <= stream(Stream, State)
where
[
% Seek to an offset relative to whence on the specified stream.
% The offset is measured in bytes.
%
pred seek(Stream::in, whence::in, int::in, State::di, State::uo) is det,
% As above, but the offset is always a 64-bit value.
%
pred seek64(Stream::in, whence::in, int64::in, State::di, State::uo) is det
].
%--------------------------------------------------%
%
% Line oriented streams.
%
% A line oriented stream is a stream that keeps track of line numbers.
%
:- typeclass line_oriented(Stream, State) <= stream(Stream, State)
where
[
% Get the current line number for the specified stream.
%
pred get_line(Stream::in, int::out, State::di, State::uo) is det,
% Set the current line number of the specified stream.
%
pred set_line(Stream::in, int::in, State::di, State::uo) is det
].
%--------------------------------------------------%
%
% Generic folds over input streams.
%
% Applies the given closure to each Unit read from the input stream
% in turn, until eof or error.
%
:- pred input_stream_fold(Stream, pred(Unit, T, T), T,
maybe_partial_res(T, Error), State, State)
<= reader(Stream, Unit, State, Error).
:- mode input_stream_fold(in, in(pred(in, in, out) is det),
in, out, di, uo) is det.
:- mode input_stream_fold(in, in(pred(in, in, out) is cc_multi),
in, out, di, uo) is cc_multi.
% Applies the given closure to each Unit read from the input stream
% in turn, until eof or error.
%
:- pred input_stream_fold_state(Stream, pred(Unit, State, State),
res(Error), State, State)
<= reader(Stream, Unit, State, Error).
:- mode input_stream_fold_state(in, in(pred(in, di, uo) is det),
out, di, uo) is det.
:- mode input_stream_fold_state(in, in(pred(in, di, uo) is cc_multi),
out, di, uo) is cc_multi.
% Applies the given closure to each Unit read from the input stream
% in turn, until eof or error.
%
:- pred input_stream_fold2_state(Stream,
pred(Unit, T, T, State, State), T, maybe_partial_res(T, Error),
State, State) <= reader(Stream, Unit, State, Error).
:- mode input_stream_fold2_state(in,
in(pred(in, in, out, di, uo) is det),
in, out, di, uo) is det.
:- mode input_stream_fold2_state(in,
in(pred(in, in, out, di, uo) is cc_multi),
in, out, di, uo) is cc_multi.
% Applies the given closure to each Unit read from the input stream
% in turn, until eof or error, or the closure returns `no' as its
% second argument.
%
:- pred input_stream_fold2_state_maybe_stop(Stream,
pred(Unit, bool, T, T, State, State),
T, maybe_partial_res(T, Error), State, State)
<= reader(Stream, Unit, State, Error).
:- mode input_stream_fold2_state_maybe_stop(in,
in(pred(in, out, in, out, di, uo) is det), in, out, di, uo) is det.
:- mode input_stream_fold2_state_maybe_stop(in,
in(pred(in, out, in, out, di, uo) is cc_multi), in, out, di, uo)
is cc_multi.
%--------------------------------------------------%
%
% Miscellaneous operations on input streams.
%
% Discard all the whitespace characters satisfying `char.is_whitespace'
% from the specified stream.
%
:- pred ignore_whitespace(Stream::in, result(Error)::out,
State::di, State::uo)
is det <= putback(Stream, char, State, Error).
%--------------------------------------------------%
%
% Miscellaneous operations on output streams.
%
% put_list(Stream, Write, Sep, List, !State).
%
% Write all the elements List to Stream separated by Sep.
%
:- pred put_list(Stream, pred(Stream, T, State, State),
pred(Stream, State, State), list(T), State, State)
<= output(Stream, State).
:- mode put_list(in, pred(in, in, di, uo) is det, pred(in, di, uo) is det,
in, di, uo) is det.
:- mode put_list(in, pred(in, in, di, uo) is cc_multi,
pred(in, di, uo) is cc_multi, in, di, uo) is cc_multi.
:- mode put_list(in, pred(in, in, di, uo) is cc_multi,
pred(in, di, uo) is det, in, di, uo) is cc_multi.
%--------------------------------------------------%
%--------------------------------------------------%
Next: stream.string_writer, Previous: store, Up: Top [Contents]