1///|
2/// header_framer returns a new Framer.
3/// The messages are sent with HTTP content length and MIME type headers.
4/// This is the format used by LSP and others.
5pub fn () -> &Framer
header_framer returns a new Framer.
The messages are sent with HTTP content length and MIME type headers.
This is the format used by LSP and others.
header_framer() -> &trait Framer {
reader(Self, &@io.ByteReader) -> &Reader
writer(Self, &@io.Writer) -> &Writer
}
Framer wraps low level byte readers and writers into jsonrpc2 message
readers and writers.
It is responsible for the framing and encoding of messages into wire form.
Framer {
6 struct HeaderFramer {
}
HeaderFramer::{ }
7}
8
9///|
10pub struct HeaderFramer {}
11
12///|
13pub struct HeaderReader {
14 &@io.ByteReader
in_ : &trait @io.ByteReader {
read_byte(Self) -> (Byte, @io.IOError?)
}
ByteReader is the interface that wraps the read_byte method.
read_byte reads and returns the next byte from the input or
any error encountered. If read_byte returns an error, no input
byte was consumed, and the returned byte value is undefined.
read_byte provides an efficient interface for byte-at-time
processing. A [Reader] that does not implement ByteReader
can be wrapped using bufio.NewReader to add this method.
@io.ByteReader
15}
16
17///|
18pub struct HeaderWriter {
19 &@io.Writer
out : &trait @io.Writer {
write(Self, @io.Slice[Byte]) -> (Int, @io.IOError?)
}
Writer is the interface that wraps the basic Write method.
Write writes len(p) bytes from p to the underlying data stream.
It returns the number of bytes written from p (0 <= n <= len(p))
and any error encountered that caused the write to stop early.
Write must return a non-None error if it returns n < len(p).
Write must not modify the slice data, even temporarily.
Implementations must not retain p.
@io.Writer
20}
21
22///|
23pub impl trait Framer {
reader(Self, &@io.ByteReader) -> &Reader
writer(Self, &@io.Writer) -> &Writer
}
Framer wraps low level byte readers and writers into jsonrpc2 message
readers and writers.
It is responsible for the framing and encoding of messages into wire form.
Framer for struct HeaderFramer {
}
HeaderFramer with (_self : HeaderFramer, in_ : &@io.ByteReader) -> &Reader
reader(HeaderFramer
_self, &@io.ByteReader
in_) -> &trait Reader {
read(Self) -> (Message?, Int64, @io.IOError?)
}
Reader abstracts the transport mechanics from the JSON RPC protocol.
A Conn reads messages from the reader it was provided on construction,
and assumes that each call to Read fully transfers a single message,
or returns an error.
A reader is not safe for concurrent use, it is expected it will be used by
a single Conn in a safe manner.
Reader {
24 struct HeaderReader {
in_: &@io.ByteReader
}
HeaderReader::{ &@io.ByteReader
in_, }
25}
26
27///|
28pub impl trait Framer {
reader(Self, &@io.ByteReader) -> &Reader
writer(Self, &@io.Writer) -> &Writer
}
Framer wraps low level byte readers and writers into jsonrpc2 message
readers and writers.
It is responsible for the framing and encoding of messages into wire form.
Framer for struct HeaderFramer {
}
HeaderFramer with (_self : HeaderFramer, out : &@io.Writer) -> &Writer
writer(HeaderFramer
_self, &@io.Writer
out) -> &trait Writer {
write(Self, Message) -> (Int64, @io.IOError?)
}
Writer abstracts the transport mechanics from the JSON RPC protocol.
A Conn writes messages using the writer it was provided on construction,
and assumes that each call to Write fully transfers a single message,
or returns an error.
A writer is not safe for concurrent use, it is expected it will be used by
a single Conn in a safe manner.
Writer {
29 struct HeaderWriter {
out: &@io.Writer
}
HeaderWriter::{ &@io.Writer
out, }
30}
31
32///|
33pub impl trait Reader {
read(Self) -> (Message?, Int64, @io.IOError?)
}
Reader abstracts the transport mechanics from the JSON RPC protocol.
A Conn reads messages from the reader it was provided on construction,
and assumes that each call to Read fully transfers a single message,
or returns an error.
A reader is not safe for concurrent use, it is expected it will be used by
a single Conn in a safe manner.
Reader for struct HeaderReader {
in_: &@io.ByteReader
}
HeaderReader with (self : HeaderReader) -> (Message?, Int64, @io.IOError?)
read(HeaderReader
self) -> (
34 enum Message {
Request(Request)
Response(Response)
BatchRequest(Array[Request])
BatchResponse(Array[Response])
}
Message covers all jsonrpc2 message types.
They share no common functionality, but are a closed set of concrete types
that are allowed to implement this interface. The message types are Request
and Response.
Message?,
35 Int64
Int64,
36 type! @io.IOError String
An IOError can be tested with equality checks.
@io.IOError?,
37) {
38 let mut Int64
total = 0L
39 let mut Int
length = 0
40 // read the header, stop on the first empty line
41 for {
42 let @io.Buffer
buf = type @io.Buffer
@io.Buffer::(size_hint~ : Int = ..) -> @io.Buffer
Buffer::new creates a new empty Buffer with an optional size hint.
The size hint is used to preallocate memory for the buffer, which can
improve performance when the size of the data to be written is known in advance.
new()
43 let (Int64
n, @io.IOError?
err) = (dst : &@io.Writer, src : &@io.ByteReader, until : Byte) -> (Int64, @io.IOError?)
copy_until copies bytes from a source reader to a destination writer
until a specified byte is encountered. It returns the number of bytes
copied and any error that occurred during the process.
@io.copy_until(@io.Buffer
buf, HeaderReader
self.&@io.ByteReader
in_, b'\n')
44 Int64
total (self : Int64, other : Int64) -> Int64
Adds two 64-bit integers together. Performs overflow checking and wrapping
according to two's complement arithmetic.
Parameters:
self : The first 64-bit integer operand.
other : The second 64-bit integer operand to add to the first.
Returns a new 64-bit integer representing the sum of the two operands.
Example:
test "Int64::op_add" {
let a = 9223372036854775807L // Int64 maximum value
let b = 1L
inspect(a + b, content="-9223372036854775808") // Wraps around to minimum value
inspect(42L + -42L, content="0")
}
+= Int64
n
45 guard @io.IOError?
err is @io.IOError?
None else {
46 return (
47 Message?
None,
48 Int64
total,
49 (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError("failed reading header line: \{@io.IOError?
err}")),
50 )
51 }
52 let @string.StringView
line = @io.Buffer
buf.(self : @io.Buffer) -> String
to_string().(self : String) -> @string.StringView
Returns the view of the string without the leading and trailing spaces.
trim_space()
53 // check we have a header line
54 if @string.StringView
line (self : @string.StringView, other : @string.StringView) -> Bool
Compares two views for equality. Returns true only if both views
have the same length and contain identical characters in the same order.
== "" {
55 break
56 }
57 let Int
colon = match @string.StringView
line.(self : @string.StringView, str : @string.StringView) -> Int?
Returns the offset (charcode index) of the first occurrence of the given
substring. If the substring is not found, it returns None.
find(":") {
58 (Int) -> Int?
Some(Int
c) => Int
c
59 Int?
None =>
60 return (
61 Message?
None,
62 Int64
total,
63 (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError("missing colon, invalid header line: '\{@string.StringView
line}'")),
64 )
65 }
66 let String
name = @string.StringView
line.(self : @string.StringView) -> String
Returns a new String containing a copy of the characters in this view.
Examples
let str = "Hello World"
let view = str[0:5] // "Hello"
inspect(view.to_string(), content="Hello")
to_string().(self : String, end~ : Int, start~ : Int = ..) -> String
Returns a new string containing characters from the original string starting
at start index up to (but not including) end index.
Parameters:
string : The source string from which to extract the substring.
start : The starting index of the substring (inclusive). Defaults to 0.
end : The ending index of the substring (exclusive). Defaults to the
length of the string.
Returns a new string containing the specified substring.
Example:
test "substring/basic" {
let s = "Hello world"
inspect(s.substring(start=0, end=5), content="Hello")
inspect(s.substring(start=6, end=11), content="world")
inspect(s.substring(), content="Hello world")
}
test "substring/empty" {
let s = "test"
inspect(s.substring(start=2, end=2), content="")
inspect("".substring(), content="")
}
test "panic substring/invalid_range" {
let s = "test"
ignore(s.substring(start=-1))
ignore(s.substring(end=5))
ignore(s.substring(start=3, end=2))
}
substring(Int
end=Int
colon)
67 let @string.StringView
value = @string.StringView
line.(self : @string.StringView) -> String
Returns a new String containing a copy of the characters in this view.
Examples
let str = "Hello World"
let view = str[0:5] // "Hello"
inspect(view.to_string(), content="Hello")
to_string().(self : String, start~ : Int, end? : Int) -> String
Returns a new string containing characters from the original string starting
at start index up to (but not including) end index.
Parameters:
string : The source string from which to extract the substring.
start : The starting index of the substring (inclusive). Defaults to 0.
end : The ending index of the substring (exclusive). Defaults to the
length of the string.
Returns a new string containing the specified substring.
Example:
test "substring/basic" {
let s = "Hello world"
inspect(s.substring(start=0, end=5), content="Hello")
inspect(s.substring(start=6, end=11), content="world")
inspect(s.substring(), content="Hello world")
}
test "substring/empty" {
let s = "test"
inspect(s.substring(start=2, end=2), content="")
inspect("".substring(), content="")
}
test "panic substring/invalid_range" {
let s = "test"
ignore(s.substring(start=-1))
ignore(s.substring(end=5))
ignore(s.substring(start=3, end=2))
}
substring(Int
start=Int
colon (self : Int, other : Int) -> Int
Adds two 32-bit signed integers. Performs two's complement arithmetic, which
means the operation will wrap around if the result exceeds the range of a
32-bit integer.
Parameters:
self : The first integer operand.
other : The second integer operand.
Returns a new integer that is the sum of the two operands. If the
mathematical sum exceeds the range of a 32-bit integer (-2,147,483,648 to
2,147,483,647), the result wraps around according to two's complement rules.
Example:
test "Int::op_add" {
inspect(42 + 1, content="43")
inspect(2147483647 + 1, content="-2147483648") // Overflow wraps around to minimum value
}
+ 1).(self : String) -> @string.StringView
Returns the view of the string without the leading and trailing spaces.
trim_space()
68 // ignore unknown headers
69 if String
name.(self : String) -> String
Converts this string to lowercase.
to_lower() (self : String, other : String) -> Bool
Tests whether two strings are equal by comparing their characters.
Parameters:
self : The first string to compare.
other : The second string to compare.
Returns true if both strings contain exactly the same sequence of
characters, false otherwise.
Example:
test "String::op_equal" {
let str1 = "hello"
let str2 = "hello"
let str3 = "world"
inspect(str1 == str2, content="true")
inspect(str1 == str3, content="false")
}
== "content-length" {
70 Int
length = try (str : String, base~ : Int) -> Int!@strconv.StrConvError
Parse a string in the given base (0, 2 to 36), return a Int number or an error.
If the ~base argument is 0, the base will be inferred by the prefix.
@strconv.parse_int!(@string.StringView
value.(self : @string.StringView) -> String
Returns a new String containing a copy of the characters in this view.
Examples
let str = "Hello World"
let view = str[0:5] // "Hello"
inspect(view.to_string(), content="Hello")
to_string(), Int
base=10) catch {
71 _ =>
72 return (
73 Message?
None,
74 Int64
total,
75 (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError("failed parsing Content-Length: \{@string.StringView
value}")),
76 )
77 }
78 if Int
length (self_ : Int, other : Int) -> Bool
<= 0 {
79 return (
80 Message?
None,
81 Int64
total,
82 (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError("invalid Content-Length: \{Int
length}")),
83 )
84 }
85 }
86 }
87 if Int
length (self : Int, other : Int) -> Bool
Compares two integers for equality.
Parameters:
self : The first integer to compare.
other : The second integer to compare.
Returns true if both integers have the same value, false otherwise.
Example:
test "Int::op_equal" {
inspect(42 == 42, content="true")
inspect(42 == -42, content="false")
}
== 0 {
88 return (Message?
None, Int64
total, (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError("missing Content-Length header")))
89 }
90 let @io.Buffer
buf = type @io.Buffer
@io.Buffer::(size_hint~ : Int) -> @io.Buffer
Buffer::new creates a new empty Buffer with an optional size hint.
The size hint is used to preallocate memory for the buffer, which can
improve performance when the size of the data to be written is known in advance.
new(Int
size_hint=Int
length)
91 let (Int64
n, @io.IOError?
err) = (dst : &@io.Writer, src : &@io.ByteReader, size : Int64) -> (Int64, @io.IOError?)
copy_size copies a specified number of bytes from a source reader to a
destination writer. It returns the number of bytes copied and any error
that occurred during the process.
@io.copy_size(@io.Buffer
buf, HeaderReader
self.&@io.ByteReader
in_, Int
length.(self : Int) -> Int64
Converts a 32-bit signed integer to a 64-bit signed integer. All 32-bit
integers can be represented exactly in 64-bit integer format, so the
conversion is lossless.
Parameters:
self : The 32-bit signed integer to be converted.
Returns a 64-bit signed integer that represents the same numerical value as
the input.
Example:
test "Int::to_int64" {
let n = 42
inspect(n.to_int64(), content="42")
let neg = -42
inspect(neg.to_int64(), content="-42")
}
to_int64())
92 Int64
total (self : Int64, other : Int64) -> Int64
Adds two 64-bit integers together. Performs overflow checking and wrapping
according to two's complement arithmetic.
Parameters:
self : The first 64-bit integer operand.
other : The second 64-bit integer operand to add to the first.
Returns a new 64-bit integer representing the sum of the two operands.
Example:
test "Int64::op_add" {
let a = 9223372036854775807L // Int64 maximum value
let b = 1L
inspect(a + b, content="-9223372036854775808") // Wraps around to minimum value
inspect(42L + -42L, content="0")
}
+= Int64
n
93 guard @io.IOError?
err is @io.IOError?
None else {
94 return (Message?
None, Int64
total, (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError("failed reading body: \{@io.IOError?
err}")))
95 }
96 let Message
msg : enum Message {
Request(Request)
Response(Response)
BatchRequest(Array[Request])
BatchResponse(Array[Response])
}
Message covers all jsonrpc2 message types.
They share no common functionality, but are a closed set of concrete types
that are allowed to implement this interface. The message types are Request
and Response.
Message = try (json : Json, path~ : @json.JsonPath = ..) -> Message!@json.JsonDecodeError
@json.from_json!((input : String) -> Json!@json.ParseError
@json.parse!(@io.Buffer
buf.(self : @io.Buffer) -> String
to_string())) catch {
97 Error
e => return (Message?
None, 0, (@io.IOError) -> @io.IOError?
Some(@io.(String) -> @io.IOError
An IOError can be tested with equality checks.
IOError(Error
e.(self : Error) -> String
to_string())))
98 }
99 ((Message) -> Message?
Some(Message
msg), Int64
n, @io.IOError?
None)
100}
101
102///|
103pub impl trait Writer {
write(Self, Message) -> (Int64, @io.IOError?)
}
Writer abstracts the transport mechanics from the JSON RPC protocol.
A Conn writes messages using the writer it was provided on construction,
and assumes that each call to Write fully transfers a single message,
or returns an error.
A writer is not safe for concurrent use, it is expected it will be used by
a single Conn in a safe manner.
Writer for struct HeaderWriter {
out: &@io.Writer
}
HeaderWriter with (self : HeaderWriter, msg : Message) -> (Int64, @io.IOError?)
write(HeaderWriter
self, Message
msg) -> (Int64
Int64, type! @io.IOError String
An IOError can be tested with equality checks.
@io.IOError?) {
104 let String
s = Message
msg.(self : Message) -> Json
to_json().(self : Json, escape_slash~ : Bool = .., indent~ : Int = ..) -> String
stringify()
105 let @io.Buffer
body = type @io.Buffer
@io.Buffer::(size_hint~ : Int = ..) -> @io.Buffer
Buffer::new creates a new empty Buffer with an optional size hint.
The size hint is used to preallocate memory for the buffer, which can
improve performance when the size of the data to be written is known in advance.
new()
106 let (Int
body_total, @io.IOError?
err) = @io.Buffer
body.(self : @io.Buffer, s : String) -> (Int, @io.IOError?)
write_string converts the MoonBit UTF-16 String to UTF-8 and
writes the bytes to the buffer.
write_string(String
s)
107 guard @io.IOError?
err is @io.IOError?
None else { return (0, @io.IOError?
err) }
108 let @io.Buffer
hdr = type @io.Buffer
@io.Buffer::(size_hint~ : Int = ..) -> @io.Buffer
Buffer::new creates a new empty Buffer with an optional size hint.
The size hint is used to preallocate memory for the buffer, which can
improve performance when the size of the data to be written is known in advance.
new()
109 let (_, @io.IOError?
err) = @io.Buffer
hdr.(self : @io.Buffer, s : String) -> (Int, @io.IOError?)
write_string converts the MoonBit UTF-16 String to UTF-8 and
writes the bytes to the buffer.
write_string("Content-Length: \{Int
body_total}\r\n\r\n")
110 guard @io.IOError?
err is @io.IOError?
None else { return (0, @io.IOError?
err) }
111 let (Int
hdr_total, @io.IOError?
err) = HeaderWriter
self.&@io.Writer
out.(&@io.Writer, @io.Slice[Byte]) -> (Int, @io.IOError?)
write(@io.Buffer
hdr.(self : @io.Buffer) -> @io.Slice[Byte]
to_slice())
112 guard @io.IOError?
err is @io.IOError?
None else { return (Int
hdr_total.(self : Int) -> Int64
Converts a 32-bit signed integer to a 64-bit signed integer. All 32-bit
integers can be represented exactly in 64-bit integer format, so the
conversion is lossless.
Parameters:
self : The 32-bit signed integer to be converted.
Returns a 64-bit signed integer that represents the same numerical value as
the input.
Example:
test "Int::to_int64" {
let n = 42
inspect(n.to_int64(), content="42")
let neg = -42
inspect(neg.to_int64(), content="-42")
}
to_int64(), @io.IOError?
err) }
113 let (Int
n, @io.IOError?
err) = HeaderWriter
self.&@io.Writer
out.(&@io.Writer, @io.Slice[Byte]) -> (Int, @io.IOError?)
write(@io.Buffer
body.(self : @io.Buffer) -> @io.Slice[Byte]
to_slice())
114 guard @io.IOError?
err is @io.IOError?
None else { return (Int
n.(self : Int) -> Int64
Converts a 32-bit signed integer to a 64-bit signed integer. All 32-bit
integers can be represented exactly in 64-bit integer format, so the
conversion is lossless.
Parameters:
self : The 32-bit signed integer to be converted.
Returns a 64-bit signed integer that represents the same numerical value as
the input.
Example:
test "Int::to_int64" {
let n = 42
inspect(n.to_int64(), content="42")
let neg = -42
inspect(neg.to_int64(), content="-42")
}
to_int64() (self : Int64, other : Int64) -> Int64
Adds two 64-bit integers together. Performs overflow checking and wrapping
according to two's complement arithmetic.
Parameters:
self : The first 64-bit integer operand.
other : The second 64-bit integer operand to add to the first.
Returns a new 64-bit integer representing the sum of the two operands.
Example:
test "Int64::op_add" {
let a = 9223372036854775807L // Int64 maximum value
let b = 1L
inspect(a + b, content="-9223372036854775808") // Wraps around to minimum value
inspect(42L + -42L, content="0")
}
+ Int
hdr_total.(self : Int) -> Int64
Converts a 32-bit signed integer to a 64-bit signed integer. All 32-bit
integers can be represented exactly in 64-bit integer format, so the
conversion is lossless.
Parameters:
self : The 32-bit signed integer to be converted.
Returns a 64-bit signed integer that represents the same numerical value as
the input.
Example:
test "Int::to_int64" {
let n = 42
inspect(n.to_int64(), content="42")
let neg = -42
inspect(neg.to_int64(), content="-42")
}
to_int64(), @io.IOError?
err) }
115 (Int
n.(self : Int) -> Int64
Converts a 32-bit signed integer to a 64-bit signed integer. All 32-bit
integers can be represented exactly in 64-bit integer format, so the
conversion is lossless.
Parameters:
self : The 32-bit signed integer to be converted.
Returns a 64-bit signed integer that represents the same numerical value as
the input.
Example:
test "Int::to_int64" {
let n = 42
inspect(n.to_int64(), content="42")
let neg = -42
inspect(neg.to_int64(), content="-42")
}
to_int64() (self : Int64, other : Int64) -> Int64
Adds two 64-bit integers together. Performs overflow checking and wrapping
according to two's complement arithmetic.
Parameters:
self : The first 64-bit integer operand.
other : The second 64-bit integer operand to add to the first.
Returns a new 64-bit integer representing the sum of the two operands.
Example:
test "Int64::op_add" {
let a = 9223372036854775807L // Int64 maximum value
let b = 1L
inspect(a + b, content="-9223372036854775808") // Wraps around to minimum value
inspect(42L + -42L, content="0")
}
+ Int
hdr_total.(self : Int) -> Int64
Converts a 32-bit signed integer to a 64-bit signed integer. All 32-bit
integers can be represented exactly in 64-bit integer format, so the
conversion is lossless.
Parameters:
self : The 32-bit signed integer to be converted.
Returns a 64-bit signed integer that represents the same numerical value as
the input.
Example:
test "Int::to_int64" {
let n = 42
inspect(n.to_int64(), content="42")
let neg = -42
inspect(neg.to_int64(), content="-42")
}
to_int64(), @io.IOError?
err)
116}
117