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