Files
mercury/extras/net/streams.m
Zoltan Somogyi 9b6390b17e Bring the programming style of extras up to date.
extras/curs/curs.m:
extras/curs/curs.panel.m:
    Make panel a separate submodule of curs, not a nested submodule.

extras/base64/base64.m:
extras/curses/mcurses.basics.m:
extras/curses/mcurses.m:
extras/curses/mcurses.misc.m:
extras/curses/mcurses.user.m:
extras/gator/evolve.m:
extras/gator/genotype.m:
extras/gator/phenotype.m:
extras/gator/tausworthe3.m:
extras/monte/dots.m:
extras/monte/geom.m:
extras/monte/hg.m:
extras/monte/monte.m:
extras/monte/rnd.m:
extras/moose/grammar.m:
extras/moose/moose.m:
extras/mopenssl/mopenssl.m:
extras/net/echo.m:
extras/net/errno.m:
extras/net/getaddrinfo.m:
extras/net/net.m:
extras/net/netdb.m:
extras/net/sockets.m:
extras/net/streams.m:
extras/net/tcp.m:
extras/net/test_lookups.m:
extras/net/types.m:
extras/odbc/odbc.m:
extras/odbc/odbc_test.m:
extras/references/README:
extras/references/reference.m:
extras/references/scoped_update.m:
extras/solver_types/library/any.m:
extras/solver_types/library/any_array.m:
extras/solver_types/library/any_assoc_list.m:
extras/solver_types/library/any_list.m:
extras/solver_types/library/any_map.m:
extras/solver_types/library/any_tree234.m:
extras/solver_types/library/any_util.m:
extras/trail/trail.m:
extras/trailed_update/samples/interpreter.m:
extras/trailed_update/samples/vqueens.m:
extras/trailed_update/tests/var_test.m:
extras/trailed_update/tr_array.m:
extras/trailed_update/tr_store.m:
extras/trailed_update/trailed_update.m:
extras/trailed_update/unsafe.m:
extras/trailed_update/var.m:
    Bring programming style up to date.
2023-03-30 21:48:10 +11:00

229 lines
6.0 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2014-2016, 2018 The Mercury Team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% Module: net.streams.
% Main Author: Paul Bone
% Stability: low
%
% Provide a streams interface for sockets.
%
%---------------------------------------------------------------------------%
:- module net.streams.
:- interface.
:- import_module int.
:- import_module io.
:- import_module stream.
:- import_module string.
:- import_module net.sockets.
%---------------------------------------------------------------------------%
:- type socket_stream.
:- func stream(socket) = socket_stream.
:- func socket(socket_stream) = socket.
:- type byte
---> byte(int).
:- type error.
:- instance error(streams.error).
:- instance stream(socket_stream, io).
%---------------------------------------------------------------------------%
:- instance input(socket_stream, io).
% XXX: This does not buffer reads, it is slow.
%
:- instance reader(socket_stream, streams.byte, io, streams.error).
:- instance reader(socket_stream, line, io, streams.error).
%---------------------------------------------------------------------------%
:- instance output(socket_stream, io).
% XXX: This does not buffer writes, it is slow.
%
:- instance writer(socket_stream, streams.byte, io).
:- instance writer(socket_stream, string, io).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module char.
:- import_module exception.
:- import_module bitmap.
:- import_module list.
:- import_module maybe.
:- import_module require.
:- type socket_stream
---> socket_stream(socket).
:- type error
---> error(string).
stream(Socket) = socket_stream(Socket).
socket(socket_stream(Socket)) = Socket.
%---------------------------------------------------------------------------%
:- instance error(streams.error) where [
error_message(error(Str)) = Str
].
:- instance stream(socket_stream, io) where [
pred(name/4) is stream_name
].
:- pred stream_name(socket_stream::in, name::out, io::di, io::uo) is det.
stream_name(socket_stream(_Socket), Name, !IO) :-
Name = "a socket".
%---------------------------------------------------------------------------%
:- instance input(socket_stream, io) where [].
:- instance reader(socket_stream, streams.byte, io, streams.error) where [
pred(get/4) is get_byte
].
:- pred get_byte(socket_stream::in, result(streams.byte, streams.error)::out,
io::di, io::uo) is det.
get_byte(socket_stream(Socket), Result, !IO) :-
read(Socket, 1, ReadResult, !IO),
(
ReadResult = ok(Bitmap),
( if num_bytes(Bitmap) = 1 then
Byte = Bitmap ^ byte(0),
Result = ok(byte(Byte))
else if num_bytes(Bitmap) = 0 then
Result = eof
else
unexpected($file, $pred,
"Read returned unexpected number of bytes")
)
;
ReadResult = eof,
Result = eof
;
ReadResult = error(String),
Result = error(error(String))
).
:- instance reader(socket_stream, line, io, streams.error) where [
pred(get/4) is get_line
].
:- pred get_line(socket_stream::in, result(line, streams.error)::out,
io::di, io::uo) is det.
get_line(Stream, Result, !IO) :-
get_chars_until_nl(Stream, [], Result0, !IO),
(
Result0 = ok(RevChars),
Result = ok(line(from_rev_char_list(RevChars)))
;
Result0 = eof,
Result = eof
;
Result0 = error(Error),
Result = error(Error)
).
:- pred get_chars_until_nl(Stream::in, list(char)::in,
result(list(char), Error)::out, State::di, State::uo) is det
<= reader(Stream, streams.byte, State, Error).
get_chars_until_nl(Stream, Chars0, Result, !IO) :-
get(Stream, ResByte, !IO),
(
ResByte = ok(byte(Byte)),
( char.from_int(Byte, Char) ->
( if
( Char = '\n'
; Char = '\r'
)
then
Result = ok(Chars0)
else
Chars1 = [Char | Chars0],
get_chars_until_nl(Stream, Chars1, Result, !IO)
)
;
unexpected($file, $pred, "Encoding error")
)
;
ResByte = eof,
Result = eof
;
ResByte = error(Error),
Result = error(Error)
).
%---------------------------------------------------------------------------%
:- instance output(socket_stream, io) where [
pred(flush/3) is flush_noop
].
:- pred flush_noop(socket_stream::in, io::di, io::uo) is det.
flush_noop(_, !IO).
% XXX: This does not buffer writes, it is slow.
%
:- instance writer(socket_stream, streams.byte, io) where [
pred(put/4) is put_byte
].
:- pred put_byte(socket_stream::in, streams.byte::in, io::di, io::uo)
is det.
put_byte(socket_stream(Socket), byte(Byte), !IO) :-
Bitmap = init(bits_per_byte) ^ byte(0) := Byte,
write(Socket, Bitmap, Result, !IO),
(
Result = ok
;
Result = error(Error),
throw(streams.error(Error))
).
:- instance writer(socket_stream, string, io) where [
pred(put/4) is put_string
].
:- pred put_string(Stream::in, string::in, State::di, State::uo) is det
<= writer(Stream, streams.byte, State).
put_string(Stream, String, !State) :-
foldl(put_char(Stream), String, !State).
:- pred put_char(Stream::in, char::in, State::di, State::uo) is det
<= writer(Stream, streams.byte, State).
put_char(Stream, Char, !State) :-
put(Stream, byte(to_int(Char)), !State).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%