///|
/// The same messages written without annotations, field by field on a
/// `PbWriter`, and read back by hand.
fn hand_mood(m : Mood) -> Int32 {
match m {
Calm => 0
Glad => 1
Grumpy => 5
}
}
///|
fn hand_mood_of(n : Int32) -> Mood {
match n {
1 => Glad
5 => Grumpy
_ => Calm
}
}
///|
fn hand_request(m : HelloRequest) -> Bytes {
let w = @moonrpc.PbWriter::new()
if m.name != "" {
w.string_(1, m.name)
}
for t in m.tags {
w.string_(4, t)
}
if m.nickname is Some(n) {
w.string_(5, n)
}
if hand_mood(m.mood) != 0 {
w.enum_(6, hand_mood(m.mood))
}
for k, v in m.extras {
let entry = @moonrpc.PbWriter::new()
entry.string_(1, k)
entry.int64(2, v)
w.message_(7, entry.to_bytes())
}
w.to_bytes()
}
///|
fn hand_reply(m : HelloReply) -> Bytes {
let w = @moonrpc.PbWriter::new()
if m.message != "" {
w.string_(1, m.message)
}
if m.calls != 0L {
w.int64(2, m.calls)
}
if !m.scores.is_empty() {
w.packed_int32(3, m.scores)
}
if m.ratio != 0.0 {
w.double_(4, m.ratio)
}
for b in m.badges {
let badge = @moonrpc.PbWriter::new()
if b.label != "" {
badge.string_(1, b.label)
}
w.message_(5, badge.to_bytes())
}
w.to_bytes()
}
///|
fn hand_int(field : Int32, v : Int32) -> Bytes {
let w = @moonrpc.PbWriter::new()
if v != 0 {
w.int32(field, v)
}
w.to_bytes()
}
///|
/// Field 1 of a message holding one `int32`.
fn hand_read_int(body : Bytes) -> Int32 raise {
let r = @moonrpc.PbReader::new(body)
let mut v = 0
while !r.eof() {
match r.read_tag() {
(1, Varint) => v = r.read_int32()
(_, wire) => r.skip(wire)
}
}
v
}
///|
fn hand_read_request(body : Bytes) -> HelloRequest raise {
let r = @moonrpc.PbReader::new(body)
let mut name = ""
let tags = []
let mut nickname = None
let mut mood = Calm
let extras = Map([])
while !r.eof() {
match r.read_tag() {
(1, LengthDelim) => name = r.read_string()
(4, LengthDelim) => tags.push(r.read_string())
(5, LengthDelim) => nickname = Some(r.read_string())
(6, Varint) => mood = hand_mood_of(r.read_int32())
(7, LengthDelim) => {
let e = @moonrpc.PbReader::new(r.read_len_delim())
let mut k = ""
let mut v = 0L
while !e.eof() {
match e.read_tag() {
(1, LengthDelim) => k = e.read_string()
(2, Varint) => v = e.read_int64()
(_, wire) => e.skip(wire)
}
}
extras[k] = v
}
(_, wire) => r.skip(wire)
}
}
{ name, tags, nickname, mood, extras, }
}
///|
/// The service registered by hand on raw bytes.
fn hand_register(server : @moonrpc.H2Server, g : Greeter) -> Unit {
server.register_unary("/greet.Greeter/SayHello", (ctx, body) => {
let req = hand_read_request(body) catch {
e => {
ctx.fail(13, "grpc: error unmarshalling request: \{e}")
return b""
}
}
if req.name == "" {
ctx.fail(3, "a name, please")
return b""
}
ctx.add_header(b"x-greeter", b"annotated")
let who = req.nickname.unwrap_or(req.name)
hand_reply({
message: "\{g.greeting}, \{who}",
calls: req.extras.get("calls").unwrap_or(9000000000),
scores: req.tags.map(t => t.length()),
ratio: 0.5,
badges: if req.mood is Grumpy {
[{ label: "grumpy", }]
} else {
[]
},
cached: false,
})
})
server.register_server_streaming("/greet.Greeter/CountTo", (_ctx, body) => {
let n = hand_read_int(body) catch { _ => 0 }
Array::makei(n, i => hand_int(1, i + 1))
})
server.register_client_streaming("/greet.Greeter/Sum", (_ctx, bodies) => {
let mut total = 0
for b in bodies {
total += hand_read_int(b) catch { _ => 0 }
}
hand_int(1, total)
})
server.register_bidi("/greet.Greeter/Echo", _ctx => {
let seen = []
{
on_message: body => {
seen.push(hand_read_int(body) catch { _ => 0 })
[]
},
on_end: () => seen.rev().map(n => hand_int(1, n)),
}
})
}
///|
fn hand_field(
name : String,
number : Int32,
type_ : @moonrpc.FieldType,
label? : @moonrpc.FieldLabel,
type_name? : String,
) -> @moonrpc.FieldDescriptor {
@moonrpc.FieldDescriptor::new(name, number, type_, label?, type_name?)
}
///|
/// The descriptor written by hand, for reflection.
fn hand_descriptor() -> @moonrpc.FileDescriptor {
let int_message = (name : String, field : String) => {
@moonrpc.MessageDescriptor::new(name, [hand_field(field, 1, TypeInt32)])
}
let rpc = (
name : String,
input : String,
output : String,
client_streaming : Bool,
server_streaming : Bool,
) => @moonrpc.MethodDescriptor::{
name,
input_type: ".greet." + input,
output_type: ".greet." + output,
client_streaming,
server_streaming,
}
@moonrpc.FileDescriptor::new(
"greeter.proto",
"greet",
messages=[
@moonrpc.MessageDescriptor::new(
"HelloRequest",
[
hand_field("name", 1, TypeString),
hand_field("tags", 4, TypeString, label=LabelRepeated),
@moonrpc.FieldDescriptor::new(
"nickname",
5,
TypeString,
oneof_index=0,
proto3_optional=true,
),
hand_field("mood", 6, TypeEnum, type_name=".greet.Mood"),
hand_field(
"extras",
7,
TypeMessage,
label=LabelRepeated,
type_name=".greet.HelloRequest.ExtrasEntry",
),
],
nested=[
@moonrpc.MessageDescriptor::new(
"ExtrasEntry",
[
hand_field("key", 1, TypeString),
hand_field("value", 2, TypeInt64),
],
map_entry=true,
),
],
oneofs=["_nickname"],
),
@moonrpc.MessageDescriptor::new(
"HelloReply",
[
hand_field("message", 1, TypeString),
hand_field("calls", 2, TypeInt64),
hand_field("scores", 3, TypeInt32, label=LabelRepeated),
hand_field("ratio", 4, TypeDouble),
hand_field(
"badges",
5,
TypeMessage,
label=LabelRepeated,
type_name=".greet.HelloReply.Badge",
),
],
nested=[
@moonrpc.MessageDescriptor::new("Badge", [
hand_field("label", 1, TypeString),
]),
],
),
int_message("Upto", "n"),
int_message("Number", "value"),
],
enums=[
{
name: "Mood",
values: [
{ name: "MOOD_CALM", number: 0, },
{ name: "MOOD_GLAD", number: 1, },
{ name: "MOOD_GRUMPY", number: 5, },
],
},
],
services=[
{
name: "Greeter",
methods: [
rpc("SayHello", "HelloRequest", "HelloReply", false, false),
rpc("CountTo", "Upto", "Number", false, true),
rpc("Sum", "Number", "Number", true, false),
rpc("Echo", "Number", "Number", true, true),
],
},
],
)
}