moonbitstack/moonnet/spec does not have a README file

    Conn

    pub(open) trait Conn {
    async fn open(self : Self, request : Request) -> Stream
    async fn send(self : Self, stream : Stream, bytes : Bytes, end~ : Bool) -> Unit
    async fn response(self : Self, stream : Stream) -> Response
    async fn read(self : Self, stream : Stream) -> Bytes?
    fn trailers(self : Self, stream : Stream) -> Array[Field]
    fn is_ready(self : Self) -> Bool
    fn kind(self : Self) -> String
    async fn close(self : Self) -> Unit
    }

    The one contract a connection presents, whatever carries it: HTTP/1.1, HTTP/2, HTTP/3 or WebSocket. Code written against this runs on any of them; an implementation is all a new protocol needs.

    An exchange is opened, the request body is sent through it, and the reply's head and body are read from it. A connection that carries one exchange at a time says so through is_ready, which a caller waits on before opening the next.

    Refused

    pub(all) suberror Refused {
    Malformed(String)
    Unsupported(String)
    Closed
    Broken(String)
    } derive(Eq,
    Debug
    )

    What a connection will not do.

    Refused::equal

    fn Refused::equal(Refused, Refused) -> Bool

    Refused::not_equal

    fn Refused::not_equal(x : Refused, y : Refused) -> Bool

    Refused::to_repr

    Body

    pub(all) enum Body {
    Empty
    Bytes(Bytes)
    Streaming
    } derive(Eq,
    Debug
    )

    Where a message's body comes from.

    Body::equal

    fn Body::equal(Body, Body) -> Bool

    Body::not_equal

    fn Body::not_equal(x : Body, y : Body) -> Bool

    Body::to_repr

    Field

    pub(all) struct Field {
    name : String
    value : String
    } derive(Eq,
    Debug
    )

    One field of a message head: the name, and the value, as they go on the wire.

    Field::equal

    fn Field::equal(Field, Field) -> Bool

    Field::key

    fn Field::key(self : Field) -> String

    The name in the form a comparison uses: HTTP field names are case-insensitive (RFC 9110 §5.1), and a lower-case copy is what every lookup compares.

    Field::new

    fn Field::new(name : String, value : String) -> Field

    Field::not_equal

    fn Field::not_equal(x : Field, y : Field) -> Bool

    Field::to_repr

    Request

    pub(all) struct Request {
    verb : String
    target : String
    fields : Array[Field]
    body : Body
    } derive(Eq,
    Debug
    )

    A request: what to ask for, and what to carry along.

    Request::equal

    fn Request::equal(Request, Request) -> Bool

    Request::field

    fn Request::field(self : Request, name : String) -> String?

    Request::new

    fn Request::new(verb : String, target : String, fields? : Array[Field], body? : Body) -> Request

    Request::not_equal

    fn Request::not_equal(x : Request, y : Request) -> Bool

    Request::to_repr

    Response

    pub(all) struct Response {
    status : Int
    fields : Array[Field]
    } derive(Eq,
    Debug
    )

    A reply head: the status and the fields. The body is read through the connection, because it may be larger than anything worth holding at once.

    Response::equal

    fn Response::equal(Response, Response) -> Bool

    Response::field

    fn Response::field(self : Response, name : String) -> String?

    Response::not_equal

    fn Response::not_equal(x : Response, y : Response) -> Bool

    Response::to_repr

    Stream

    pub(all) struct Stream {
    id : Int
    } derive(Eq,
    Debug
    )

    One exchange on a connection, named by the connection rather than by the protocol underneath: on a connection that carries one exchange at a time it is 1, and on one that multiplexes it is whatever that connection gave out.

    Stream::equal

    fn Stream::equal(Stream, Stream) -> Bool

    Stream::not_equal

    fn Stream::not_equal(x : Stream, y : Stream) -> Bool

    Stream::to_repr

    call

    async fn call(conn : &Conn, request : Request) -> (Response, Bytes)

    Send request and read the whole reply, body included. The body is held in memory, so this is for replies of a bounded size; a reply read as it arrives goes through the methods of the contract one at a time.

    find

    fn find(fields : Array[Field], name : String) -> String?

    The first field named name, matched without regard to case.

    lines

    fn lines(fields : Array[Field]) -> String

    name: value lines, the form a head is shown in by a person reading a log.

    read_to_end

    async fn read_to_end(conn : &Conn, stream : Stream, limit? : Int) -> Bytes

    Read the rest of an exchange's body and join it into one run of octets. limit is the most this will hold: a reply larger than that is refused rather than buffered without end.

    table

    fn table(fields : Array[Field]) -> Map[String, String]

    Every field of a head as one lower-cased name to its value, the last one winning, as a map lookup would.

    Source Files