diff --git a/Cargo.toml b/Cargo.toml index 38e9cb9d1..b682b35eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "capnpc", "capnp-futures", "capnp-rpc", + "capnp-json", # testing and examples "async-byte-channel", @@ -30,6 +31,7 @@ members = [ "example/addressbook", "example/addressbook_send", "example/fill_random_values", + "capnp-json/test", ] default-members = [ "capnp", diff --git a/capnp-json/Cargo.toml b/capnp-json/Cargo.toml new file mode 100644 index 000000000..eea33e87d --- /dev/null +++ b/capnp-json/Cargo.toml @@ -0,0 +1,20 @@ +[package] + +name = "capnp-json" +version = "0.23.0" +authors = [ "Ben Jackson " ] +license = "MIT" +description = "implementation of the Cap'n Proto JSON codec in rust" +repository = "https://github.com/capnproto/capnproto-rust" +documentation = "https://docs.rs/capnp-rpc/" +categories = ["network-programming"] +autoexamples = false +edition = "2021" + +readme = "README.md" + +[dependencies] +capnp = {version = "0.23.0", path = "../capnp"} + +#[lints] +#workspace = true diff --git a/capnp-json/json.capnp b/capnp-json/json.capnp new file mode 100644 index 000000000..e5d1870c0 --- /dev/null +++ b/capnp-json/json.capnp @@ -0,0 +1,127 @@ +# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0x8ef99297a43a5e34; + +$import "/capnp/c++.capnp".namespace("capnp::json"); + +struct Value { + union { + null @0 :Void; + boolean @1 :Bool; + number @2 :Float64; + string @3 :Text; + array @4 :List(Value); + object @5 :List(Field); + # Standard JSON values. + + call @6 :Call; + # Non-standard: A "function call", applying a named function (named by a single identifier) + # to a parameter list. Examples: + # + # BinData(0, "Zm9vCg==") + # ISODate("2015-04-15T08:44:50.218Z") + # + # Mongo DB users will recognize the above as exactly the syntax Mongo uses to represent BSON + # "binary" and "date" types in text, since JSON has no analog of these. This is basically the + # reason this extension exists. We do NOT recommend using `call` unless you specifically need + # to be compatible with some silly format that uses this syntax. + + raw @7 :Text; + # Used to indicate that the text should be written directly to the output without + # modifications. Use this if you have an already serialized JSON value and don't want + # to feel the cost of deserializing the value just to serialize it again. + # + # The parser will never produce a `raw` value -- this is only useful for serialization. + # + # WARNING: You MUST ensure that the value is valid stand-alone JSOn. It will not be verified. + # Invalid JSON could mjake the whole message unparsable. Worse, a malicious raw value could + # perform JSON injection attacks. Make sure that the value was produced by a trustworthy JSON + # encoder. + } + + struct Field { + name @0 :Text; + value @1 :Value; + } + + struct Call { + function @0 :Text; + params @1 :List(Value); + } +} + +# ======================================================================================== +# Annotations to control parsing. Typical usage: +# +# using Json = import "/capnp/compat/json.capnp"; +# +# And then later on: +# +# myField @0 :Text $Json.name("my_field"); + +annotation name @0xfa5b1fd61c2e7c3d (field, enumerant, method, group, union) :Text; +# Define an alternative name to use when encoding the given item in JSON. This can be used, for +# example, to use snake_case names where needed, even though Cap'n Proto uses strictly camelCase. +# +# (However, because JSON is derived from JavaScript, you *should* use camelCase names when +# defining JSON-based APIs. But, when supporting a pre-existing API you may not have a choice.) + +annotation flatten @0x82d3e852af0336bf (field, group, union) :FlattenOptions; +# Specifies that an aggregate field should be flattened into its parent. +# +# In order to flatten a member of a union, the union (or, for an anonymous union, the parent +# struct type) must have the $jsonDiscriminator annotation. +# +# TODO(someday): Maybe support "flattening" a List(Value.Field) as a way to support unknown JSON +# fields? + +struct FlattenOptions { + prefix @0 :Text = ""; + # Optional: Adds the given prefix to flattened field names. +} + +annotation discriminator @0xcfa794e8d19a0162 (struct, union) :DiscriminatorOptions; +# Specifies that a union's variant will be decided not by which fields are present, but instead +# by a special discriminator field. The value of the discriminator field is a string naming which +# variant is active. This allows the members of the union to have the $jsonFlatten annotation, or +# to all have the same name. + +struct DiscriminatorOptions { + name @0 :Text; + # The name of the discriminator field. Defaults to matching the name of the union. + + valueName @1 :Text; + # If non-null, specifies that the union's value shall have the given field name, rather than the + # value's name. In this case the union's variant can only be determined by looking at the + # discriminant field, not by inspecting which value field is present. + # + # It is an error to use `valueName` while also declaring some variants as $flatten. +} + +annotation base64 @0xd7d879450a253e4b (field) :Void; +# Place on a field of type `Data` to indicate that its JSON representation is a Base64 string. + +annotation hex @0xf061e22f0ae5c7b5 (field) :Void; +# Place on a field of type `Data` to indicate that its JSON representation is a hex string. + +annotation notification @0xa0a054dea32fd98c (method) :Void; +# Indicates that this method is a JSON-RPC "notification", meaning it expects no response. diff --git a/capnp-json/src/data.rs b/capnp-json/src/data.rs new file mode 100644 index 000000000..2805d4b36 --- /dev/null +++ b/capnp-json/src/data.rs @@ -0,0 +1,120 @@ +// We don't want to pull in base64 crate just for this. So hand-rolling a +// base64 codec. +pub mod base64 { + const BASE64_CHARS: &[u8; 64] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + pub fn encode(data: &[u8]) -> String { + let mut encoded = String::with_capacity(data.len().div_ceil(3) * 4); + for chunk in data.chunks(3) { + #[allow(clippy::get_first)] + let b0 = chunk.get(0).copied().unwrap_or(0); + let b1 = chunk.get(1).copied().unwrap_or(0); + let b2 = chunk.get(2).copied().unwrap_or(0); + let n = ((b0 as u32) << 16) | ((b1 as u32) << 8) | (b2 as u32); + let c0 = BASE64_CHARS[((n >> 18) & 0x3F) as usize]; + let c1 = BASE64_CHARS[((n >> 12) & 0x3F) as usize]; + let c2 = if chunk.len() > 1 { + BASE64_CHARS[((n >> 6) & 0x3F) as usize] + } else { + b'=' + }; + let c3 = if chunk.len() > 2 { + BASE64_CHARS[(n & 0x3F) as usize] + } else { + b'=' + }; + encoded.push(c0 as char); + encoded.push(c1 as char); + encoded.push(c2 as char); + encoded.push(c3 as char); + } + encoded + } + + pub fn decode(data: &str) -> capnp::Result> { + let bytes = data.as_bytes(); + if !bytes.len().is_multiple_of(4) { + return Err(capnp::Error::failed( + "Base64 string length must be a multiple of 4".into(), + )); + } + let mut decoded = Vec::with_capacity(bytes.len() / 4 * 3); + for chunk in bytes.chunks(4) { + let mut n: u32 = 0; + let mut padding = 0; + for &c in chunk { + n <<= 6; + match c { + b'A'..=b'Z' => n |= (c - b'A') as u32, + b'a'..=b'z' => n |= (c - b'a' + 26) as u32, + b'0'..=b'9' => n |= (c - b'0' + 52) as u32, + b'+' => n |= 62, + b'/' => n |= 63, + b'=' => { + n |= 0; + padding += 1; + } + _ => { + return Err(capnp::Error::failed(format!( + "Invalid base64 character: {}", + c as char + ))); + } + } + } + decoded.push(((n >> 16) & 0xFF) as u8); + if padding < 2 { + decoded.push(((n >> 8) & 0xFF) as u8); + } + if padding < 1 { + decoded.push((n & 0xFF) as u8); + } + } + Ok(decoded) + } +} + +// We don't want to pull in hex crate just for this. So hand-rolling a +// hex codec. +pub mod hex { + const HEX_CHARS: &[u8; 16] = b"0123456789abcdef"; + fn hex_char_to_value(c: u8) -> capnp::Result { + match c { + b'0'..=b'9' => Ok(c - b'0'), + b'a'..=b'f' => Ok(c - b'a' + 10), + b'A'..=b'F' => Ok(c - b'A' + 10), + _ => Err(capnp::Error::failed(format!( + "Invalid hex character: {}", + c as char + ))), + } + } + + pub fn encode(data: &[u8]) -> String { + let mut encoded = String::with_capacity(data.len() * 2); + for &byte in data { + let high = HEX_CHARS[(byte >> 4) as usize]; + let low = HEX_CHARS[(byte & 0x0F) as usize]; + encoded.push(high as char); + encoded.push(low as char); + } + encoded + } + + pub fn decode(data: &str) -> capnp::Result> { + if !data.len().is_multiple_of(2) { + return Err(capnp::Error::failed( + "Hex string must have even length".into(), + )); + } + let mut decoded = Vec::with_capacity(data.len() / 2); + let bytes = data.as_bytes(); + for i in (0..data.len()).step_by(2) { + let high = hex_char_to_value(bytes[i])?; + let low = hex_char_to_value(bytes[i + 1])?; + decoded.push((high << 4) | low); + } + Ok(decoded) + } +} diff --git a/capnp-json/src/decode.rs b/capnp-json/src/decode.rs new file mode 100644 index 000000000..8149095a4 --- /dev/null +++ b/capnp-json/src/decode.rs @@ -0,0 +1,804 @@ +// Deserialisation +use super::data::{base64, hex}; +use super::json_capnp; +use super::{DataEncoding, EncodingOptions}; + +enum ParseError { + UnexpectedEndOfInput, + InvalidToken(char), + Other(String), +} + +impl From for capnp::Error { + fn from(err: ParseError) -> Self { + match err { + ParseError::UnexpectedEndOfInput => { + capnp::Error::failed("Unexpected end of input while parsing JSON".into()) + } + ParseError::InvalidToken(c) => { + capnp::Error::failed(format!("Invalid token '{c}' while parsing JSON")) + } + // TODO: Use better values here? + ParseError::Other(msg) => capnp::Error::failed(msg), + } + } +} + +use std::collections::HashMap; + +// FIXME: The String valued below could be Cow<'input, str> as they only really +// need to be allocated if the input contains escaped characters. That would be +// a little more tricky lower down, but not by a lot. +enum JsonValue { + Null, + Boolean(bool), + Number(f64), + String(String), + Array(Vec), + Object(HashMap), + + DataBuffer(Vec), // HACK: This is so we have somewhere to store the data + // temporarily when we are decoding data fields into + // Readers +} + +struct Parser +where + I: Iterator, +{ + // FIXME: By using an iter over char here, we restrict ourselves to not + // being able to use string slices for must of the parsing. THis is piggy. + // It would be better to just have a &str and an index probably. + input_iter: std::iter::Peekable>, +} + +impl Parser +where + I: Iterator, +{ + fn new(iter: I) -> Self { + Self { + input_iter: iter.fuse().peekable(), + } + } + + /// Advance past any whitespace and peek at next value + fn peek_next(&mut self) -> Option { + self.discard_whitespace(); + self.peek() + } + + /// Peek at the current value + fn peek(&mut self) -> Option { + self.input_iter.peek().copied() + } + + /// Consume the current value + fn advance(&mut self) -> capnp::Result { + self.input_iter + .next() + .ok_or(ParseError::UnexpectedEndOfInput.into()) + } + + /// Consume the current value if it matches `c`, otherwise error + fn consume(&mut self, c: char) -> capnp::Result { + match self.advance()? { + p if p == c => Ok(p), + p => Err(ParseError::InvalidToken(p).into()), + } + } + + /// Advance past any whitespace and consume the current value if it matches `c`, otherwise error + fn consume_next(&mut self, c: char) -> capnp::Result { + self.discard_whitespace(); + match self.advance()? { + p if p == c => Ok(p), + p => Err(ParseError::InvalidToken(p).into()), + } + } + + fn discard_whitespace(&mut self) { + while let Some(c) = self.peek() { + if c.is_whitespace() { + self.advance().ok(); + } else { + break; + } + } + } + + fn parse_value(&mut self) -> capnp::Result { + match self.peek_next() { + None => Err(ParseError::UnexpectedEndOfInput.into()), + Some('n') => { + self.advance()?; + self.consume('u')?; + self.consume('l')?; + self.consume('l')?; + Ok(JsonValue::Null) + } + Some('t') => { + self.advance()?; + self.consume('r')?; + self.consume('u')?; + self.consume('e')?; + Ok(JsonValue::Boolean(true)) + } + Some('f') => { + self.advance()?; + self.consume('a')?; + self.consume('l')?; + self.consume('s')?; + self.consume('e')?; + Ok(JsonValue::Boolean(false)) + } + Some('\"') => Ok(JsonValue::String(self.parse_string()?)), + Some('0'..='9') | Some('-') => { + let num_str = self.parse_number()?; + let num = num_str + .parse::() + .map_err(|e| ParseError::Other(format!("Invalid number format: {e}")))?; + Ok(JsonValue::Number(num)) + } + Some('[') => { + self.advance()?; + let mut items = Vec::new(); + let mut require_comma = false; + while self.peek_next().is_some_and(|c| c != ']') { + if require_comma { + self.consume(',')?; + } + require_comma = true; + let item = self.parse_value()?; + items.push(item); + } + self.consume_next(']')?; + Ok(JsonValue::Array(items)) + } + Some('{') => { + self.advance()?; + let mut members = HashMap::new(); + let mut require_comma = false; + while self.peek_next().is_some_and(|c| c != '}') { + if require_comma { + self.consume(',')?; + } + require_comma = true; + let key = self.parse_string()?; + self.consume_next(':')?; + let value = self.parse_value()?; + if members.insert(key.clone(), value).is_some() { + return Err( + ParseError::Other(format!("Duplicate key in object: {key}")).into() + ); + } + } + self.consume_next('}')?; + Ok(JsonValue::Object(members)) + } + Some(c) => Err(ParseError::InvalidToken(c).into()), + } + } + + fn parse_string(&mut self) -> capnp::Result { + self.consume_next('\"')?; + let mut result = String::new(); + loop { + let c = self.advance()?; + match c { + '\"' => return Ok(result), + '\\' => { + let escaped = self.advance()?; + match escaped { + '\"' => result.push('\"'), + '\\' => result.push('\\'), + '/' => result.push('/'), + 'b' => result.push('\u{08}'), + 'f' => result.push('\u{0C}'), + 'n' => result.push('\n'), + 'r' => result.push('\r'), + 't' => result.push('\t'), + 'u' => { + let mut hex = String::new(); + for _ in 0..4 { + hex.push(self.advance()?); + } + let code_point = u16::from_str_radix(&hex, 16).map_err(|_| { + ParseError::Other(format!("Invalid unicode escape: \\u{hex}")) + })?; + if let Some(ch) = std::char::from_u32(code_point as u32) { + result.push(ch); + } else { + return Err(ParseError::Other(format!( + "Invalid unicode code point: \\u{hex}" + )) + .into()); + } + } + other => { + return Err(ParseError::Other(format!( + "Invalid escape character: \\{other}" + )) + .into()); + } + } + } + other => result.push(other), + } + } + } + + fn parse_number(&mut self) -> capnp::Result { + let mut num_str = String::new(); + if self.peek_next().is_some_and(|c| c == '-') { + num_str.push(self.advance()?); + } + while self.peek().is_some_and(|c| c.is_ascii_digit()) { + num_str.push(self.advance()?); + } + if self.peek().is_some_and(|c| c == '.') { + num_str.push(self.advance()?); + while self.peek().is_some_and(|c| c.is_ascii_digit()) { + num_str.push(self.advance()?); + } + } + if self.peek().is_some_and(|c| c == 'e' || c == 'E') { + num_str.push(self.advance()?); + if self.peek().is_some_and(|c| c == '+' || c == '-') { + num_str.push(self.advance()?); + } + while self.peek().is_some_and(|c| c.is_ascii_digit()) { + num_str.push(self.advance()?); + } + } + Ok(num_str) + } +} + +pub fn parse(json: &str, builder: capnp::dynamic_struct::Builder<'_>) -> capnp::Result<()> { + let mut parser = Parser::new(json.chars()); + let value = parser.parse_value()?; + let meta = EncodingOptions { + prefix: &std::borrow::Cow::Borrowed(""), + name: "", + flatten: None, + discriminator: None, + data_encoding: DataEncoding::Default, + }; + let JsonValue::Object(mut value) = value else { + return Err(capnp::Error::failed( + "Top-level JSON value must be an object".into(), + )); + }; + decode_struct(&mut value, builder, &meta) +} + +fn decode_primitive<'json, 'meta>( + field_value: &'json mut JsonValue, + field_type: &'meta capnp::introspect::Type, + field_meta: &'meta EncodingOptions, +) -> capnp::Result> { + match field_type.which() { + capnp::introspect::TypeVariant::Void => { + if !matches!(field_value, JsonValue::Null) { + Err(capnp::Error::failed(format!( + "Expected null for void field {}", + field_meta.name + ))) + } else { + Ok(capnp::dynamic_value::Reader::Void) + } + } + capnp::introspect::TypeVariant::Bool => { + let JsonValue::Boolean(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected boolean for field {}", + field_meta.name + ))); + }; + Ok((*field_value).into()) + } + capnp::introspect::TypeVariant::Int8 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as i8).into()) + } + capnp::introspect::TypeVariant::Int16 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as i16).into()) + } + capnp::introspect::TypeVariant::Int32 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as i32).into()) + } + capnp::introspect::TypeVariant::Int64 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as i64).into()) + } + capnp::introspect::TypeVariant::UInt8 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as u8).into()) + } + capnp::introspect::TypeVariant::UInt16 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as u16).into()) + } + capnp::introspect::TypeVariant::UInt32 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as u32).into()) + } + capnp::introspect::TypeVariant::UInt64 => { + let JsonValue::Number(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + }; + Ok((*field_value as u64).into()) + } + capnp::introspect::TypeVariant::Float32 => { + let field_value = match field_value { + JsonValue::Number(field_value) => *field_value as f32, + JsonValue::String(field_value) => match field_value.as_str() { + "NaN" => f32::NAN, + "Infinity" => f32::INFINITY, + "-Infinity" => f32::NEG_INFINITY, + _ => { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + } + }, + _ => { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + } + }; + Ok(field_value.into()) + } + capnp::introspect::TypeVariant::Float64 => { + let field_value = match field_value { + JsonValue::Number(field_value) => *field_value, + JsonValue::String(field_value) => match field_value.as_str() { + "NaN" => f64::NAN, + "Infinity" => f64::INFINITY, + "-Infinity" => f64::NEG_INFINITY, + _ => { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + } + }, + _ => { + return Err(capnp::Error::failed(format!( + "Expected number for field {}", + field_meta.name + ))); + } + }; + Ok(field_value.into()) + } + capnp::introspect::TypeVariant::Text => { + let JsonValue::String(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected string for field {}", + field_meta.name + ))); + }; + Ok((*field_value.as_str()).into()) + } + capnp::introspect::TypeVariant::Enum(enum_schema) => match field_value { + JsonValue::String(field_value) => { + let enum_schema = capnp::schema::EnumSchema::new(enum_schema); + let Some(enum_value) = enum_schema.get_enumerants()?.iter().find(|e| { + // FIXME: this is naive, enum values can be renamed using + // $Json.name so we need to handle that + + let annotations = e.get_annotations().ok(); + let value = annotations + .and_then(|anns| { + anns.iter() + .find(|a| a.get_id() == json_capnp::name::ID) + .and_then(|a| { + a.get_value() + .ok() + .map(|v| v.downcast::().to_str().ok()) + }) + }) + .unwrap_or(e.get_proto().get_name().ok().and_then(|n| n.to_str().ok())); + value.is_some_and(|s| s == field_value) + }) else { + return Err(capnp::Error::failed(format!( + "Invalid enum value '{}' for field {}", + field_value, field_meta.name + ))); + }; + + Ok(capnp::dynamic_value::Reader::Enum( + capnp::dynamic_value::Enum::new( + enum_value.get_ordinal(), + enum_value.get_containing_enum(), + ), + )) + } + JsonValue::Number(enum_value) => { + let enum_schema = capnp::schema::EnumSchema::new(enum_schema); + Ok(capnp::dynamic_value::Reader::Enum( + capnp::dynamic_value::Enum::new(*enum_value as u16, enum_schema), + )) + } + _ => Err(capnp::Error::failed(format!( + "Expected string or number for enum field {}", + field_meta.name + ))), + }, + capnp::introspect::TypeVariant::Data => match field_meta.data_encoding { + // The reason we have this ugly DataBuffer hack is to ensure that we + // can return a Reader from this function whose lifetime is tied to + // the field_value, as there is no other buffer we can use. We don't + // currently support Orphans, but if we did, most of this Reader + // dance could probably be avoided. + DataEncoding::Default => { + let JsonValue::Array(data_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected array for data field {}", + field_meta.name + ))); + }; + let mut data = Vec::with_capacity(data_value.len()); + for byte_value in data_value.drain(..) { + let JsonValue::Number(byte_value) = byte_value else { + return Err(capnp::Error::failed(format!( + "Expected number for data byte in field {}", + field_meta.name + ))); + }; + data.push(byte_value as u8); + } + *field_value = JsonValue::DataBuffer(data); + Ok(capnp::dynamic_value::Reader::Data(match field_value { + JsonValue::DataBuffer(ref data) => data.as_slice(), + _ => unreachable!(), + })) + } + DataEncoding::Base64 => { + let JsonValue::String(data_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected string for base64 data field {}", + field_meta.name + ))); + }; + *field_value = JsonValue::DataBuffer(base64::decode(data_value)?); + Ok(capnp::dynamic_value::Reader::Data(match field_value { + JsonValue::DataBuffer(ref data) => data.as_slice(), + _ => unreachable!(), + })) + } + DataEncoding::Hex => { + let JsonValue::String(data_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected string for hex data field {}", + field_meta.name + ))); + }; + *field_value = JsonValue::DataBuffer(hex::decode(data_value)?); + Ok(capnp::dynamic_value::Reader::Data(match field_value { + JsonValue::DataBuffer(ref data) => data.as_slice(), + _ => unreachable!(), + })) + } + }, + _ => Err(capnp::Error::failed(format!( + "Unsupported primitive type for field {}", + field_meta.name + ))), + } +} + +fn decode_list( + mut field_values: Vec, + mut list_builder: capnp::dynamic_list::Builder, + field_meta: &EncodingOptions, +) -> capnp::Result<()> { + match list_builder.element_type().which() { + capnp::introspect::TypeVariant::Struct(_sub_element_schema) => { + for (i, item_value) in field_values.drain(..).enumerate() { + let JsonValue::Object(mut item_value) = item_value else { + return Err(capnp::Error::failed(format!( + "Expected object for struct list field {}", + field_meta.name + ))); + }; + let struct_builder = list_builder + .reborrow() + .get(i as u32)? + .downcast::(); + decode_struct(&mut item_value, struct_builder, field_meta)?; + } + Ok(()) + } + capnp::introspect::TypeVariant::List(_sub_element_type) => { + for (i, item_value) in field_values.drain(..).enumerate() { + let JsonValue::Array(item_value) = item_value else { + return Err(capnp::Error::failed(format!( + "Expected array for list field {}", + field_meta.name + ))); + }; + let sub_element_builder = list_builder + .reborrow() + .init(i as u32, item_value.len() as u32)? + .downcast::(); + decode_list(item_value, sub_element_builder, field_meta)?; + } + Ok(()) + } + _ => { + for (i, mut item_value) in field_values.drain(..).enumerate() { + list_builder.set( + i as u32, + decode_primitive(&mut item_value, &list_builder.element_type(), field_meta)?, + )?; + } + Ok(()) + } + } +} + +fn decode_struct( + value: &mut HashMap, + mut builder: capnp::dynamic_struct::Builder<'_>, + meta: &EncodingOptions, +) -> capnp::Result<()> { + let field_prefix = if let Some(flatten_options) = &meta.flatten { + std::borrow::Cow::Owned(format!( + "{}{}", + meta.prefix, + flatten_options.get_prefix()?.to_str()? + )) + } else { + std::borrow::Cow::Borrowed("") + }; + + fn decode_member( + mut builder: capnp::dynamic_struct::Builder<'_>, + field: capnp::schema::Field, + field_meta: &EncodingOptions, + value: &mut HashMap, + value_name: &str, + ) -> capnp::Result<()> { + match field.get_type().which() { + capnp::introspect::TypeVariant::Struct(_struct_schema) => { + let struct_builder = builder + .reborrow() + .init(field)? + .downcast::(); + if field_meta.flatten.is_none() { + let field_value = match value.remove(value_name) { + Some(v) => v, + None => return Ok(()), + }; + + let JsonValue::Object(mut field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected object for field {}", + field_meta.name + ))); + }; + decode_struct(&mut field_value, struct_builder, field_meta)?; + } else { + // Flattened struct; pass the JsonValue at this level down + decode_struct(value, struct_builder, field_meta)?; + } + } + capnp::introspect::TypeVariant::List(_element_type) => { + let Some(field_value) = value.remove(value_name) else { + return Ok(()); + }; + + let JsonValue::Array(field_value) = field_value else { + return Err(capnp::Error::failed(format!( + "Expected array for field {}", + field_meta.name + ))); + }; + let list_builder = builder + .reborrow() + .initn(field, field_value.len() as u32)? + .downcast::(); + decode_list(field_value, list_builder, field_meta)?; + } + + capnp::introspect::TypeVariant::AnyPointer => { + return Err(capnp::Error::unimplemented( + "AnyPointer cannot be represented in JSON".into(), + )) + } + capnp::introspect::TypeVariant::Capability => { + return Err(capnp::Error::unimplemented( + "Capability cannot be represented in JSON".into(), + )) + } + + _ => { + let Some(mut field_value) = value.remove(value_name) else { + return Ok(()); + }; + + builder.set( + field, + decode_primitive(&mut field_value, &field.get_type(), field_meta)?, + )?; + } + } + Ok(()) + } + + for field in builder.get_schema().get_non_union_fields()? { + let field_meta = EncodingOptions::from_field(&field_prefix, &field)?; + let field_name = format!("{}{}", field_prefix, field_meta.name); + + decode_member(builder.reborrow(), field, &field_meta, value, &field_name)?; + } + + let struct_discriminator = builder + .get_schema() + .get_annotations()? + .iter() + .find(|a| a.get_id() == json_capnp::discriminator::ID) + .and_then(|annotation| { + annotation + .get_value() + .ok() + .map(|v| v.downcast_struct::()) + }); + let discriminator = meta.discriminator.or(struct_discriminator); + + // FIXME: refactor this to only loop through union memberes once; each + // iteration check if it matches the discriminant, *or* the requisite + // named field is present, then decode and break; + let discriminant = match discriminator { + Some(discriminator) => { + let discriminator_name = if discriminator.has_name() { + discriminator.get_name()?.to_str()? + } else { + meta.name + }; + let field_name = format!("{field_prefix}{discriminator_name}"); + if let Some(JsonValue::String(discriminant)) = value.remove(&field_name) { + Some(discriminant) + } else { + None + } + } + None => None, + }; + + let discriminant = match discriminant { + Some(discriminant) => Some(discriminant), + None => { + // find the first field that exists matching a union field? + let mut discriminant = None; + for field in builder.get_schema().get_union_fields()? { + let field_meta = EncodingOptions::from_field(meta.prefix, &field)?; + let field_name = format!("{}{}", field_prefix, field_meta.name); + if value.contains_key(&field_name) { + discriminant = Some(field_meta.name.to_string()); + break; + } + } + discriminant + } + }; + + if let Some(discriminant) = discriminant { + for field in builder.get_schema().get_union_fields()? { + let field_meta = EncodingOptions::from_field(meta.prefix, &field)?; + if field_meta.name != discriminant { + continue; + } + let value_name = if let Some(discriminator) = discriminator { + if discriminator.has_value_name() { + discriminator.get_value_name()?.to_str()? + } else { + field_meta.name + } + } else { + field_meta.name + }; + if matches!( + field.get_type().which(), + capnp::introspect::TypeVariant::Void + ) { + // Void union member; just set the discriminant + builder + .reborrow() + .set(field, capnp::dynamic_value::Reader::Void)?; + break; + } + decode_member(builder.reborrow(), field, &field_meta, value, value_name)?; + break; + } + } + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_parse_string() -> capnp::Result<()> { + let json = r#""Hello, World!""#; + + let mut parser = Parser::new(json.chars()); + let value = parser.parse_value()?; + + assert!(matches!(value, JsonValue::String(s) if s == "Hello, World!")); + Ok(()) + } + + #[test] + fn test_parse_string_with_special_chars() -> capnp::Result<()> { + let json = r#""Hełło,\nWorld!\"†ęś†: \u0007""#; + + let mut parser = Parser::new(json.chars()); + let value = parser.parse_value()?; + + assert!(matches!(value, JsonValue::String(s) if s == "Hełło,\nWorld!\"†ęś†: \u{0007}")); + + let json = + r#"{"value":"tab: \t, newline: \n, carriage return: \r, quote: \", backslash: \\"}"#; + let mut parser = Parser::new(json.chars()); + let value = parser.parse_value()?; + let JsonValue::Object(map) = value else { + panic!("Expected object at top level"); + }; + let Some(JsonValue::String(s)) = map.get("value") else { + panic!("Expected string value for 'value' key"); + }; + assert_eq!( + s, + "tab: \t, newline: \n, carriage return: \r, quote: \", backslash: \\" + ); + Ok(()) + } +} diff --git a/capnp-json/src/encode.rs b/capnp-json/src/encode.rs new file mode 100644 index 000000000..bf643c694 --- /dev/null +++ b/capnp-json/src/encode.rs @@ -0,0 +1,296 @@ +use super::data::{base64, hex}; +use super::json_capnp; +use super::{DataEncoding, EncodingOptions}; + +pub fn serialize_json_to<'reader, W>( + writer: &mut W, + reader: impl Into>, +) -> capnp::Result<()> +where + W: std::io::Write, +{ + let meta = EncodingOptions { + prefix: &std::borrow::Cow::Borrowed(""), + name: "", + flatten: None, + discriminator: None, + data_encoding: DataEncoding::Default, + }; + serialize_value_to(writer, reader.into(), &meta, &mut true) +} + +fn serialize_value_to( + writer: &mut W, + reader: capnp::dynamic_value::Reader<'_>, + meta: &EncodingOptions<'_, '_>, + first: &mut bool, +) -> capnp::Result<()> +where + W: std::io::Write, +{ + match reader { + capnp::dynamic_value::Reader::Void => write!(writer, "null").map_err(|e| e.into()), + capnp::dynamic_value::Reader::Bool(value) => if value { + write!(writer, "true") + } else { + write!(writer, "false") + } + .map_err(|e| e.into()), + capnp::dynamic_value::Reader::Int8(value) => write_signed_number(writer, value as i64), + capnp::dynamic_value::Reader::Int16(value) => write_signed_number(writer, value as i64), + capnp::dynamic_value::Reader::Int32(value) => write_signed_number(writer, value as i64), + capnp::dynamic_value::Reader::Int64(value) => write_signed_number(writer, value), + capnp::dynamic_value::Reader::UInt8(value) => write_unsigned_number(writer, value as u64), + capnp::dynamic_value::Reader::UInt16(value) => write_unsigned_number(writer, value as u64), + capnp::dynamic_value::Reader::UInt32(value) => write_unsigned_number(writer, value as u64), + capnp::dynamic_value::Reader::UInt64(value) => write_unsigned_number(writer, value), + capnp::dynamic_value::Reader::Float32(value) => write_float_number(writer, value as f64), + capnp::dynamic_value::Reader::Float64(value) => write_float_number(writer, value), + capnp::dynamic_value::Reader::Enum(value) => { + if let Some(enumerant) = value.get_enumerant()? { + let value = enumerant + .get_annotations()? + .iter() + .find(|a| a.get_id() == json_capnp::name::ID) + .and_then(|a| { + a.get_value() + .ok() + .map(|v| v.downcast::().to_str()) + }) + .unwrap_or(enumerant.get_proto().get_name()?.to_str()); + write_string(writer, value?) + } else { + write_unsigned_number(writer, value.get_value() as u64) + } + } + capnp::dynamic_value::Reader::Text(reader) => write_string(writer, reader.to_str()?), + capnp::dynamic_value::Reader::Data(data) => write_data(writer, data, meta.data_encoding), + capnp::dynamic_value::Reader::Struct(reader) => write_object(writer, reader, meta, first), + capnp::dynamic_value::Reader::List(reader) => write_array(writer, reader.iter(), meta), + capnp::dynamic_value::Reader::AnyPointer(_) => Err(capnp::Error::unimplemented( + "AnyPointer cannot be represented in JSON".into(), + )), + capnp::dynamic_value::Reader::Capability(_) => Err(capnp::Error::unimplemented( + "Capability cannot be represented in JSON".into(), + )), + } +} + +// TODO: use capnp::io::Write ? +fn write_unsigned_number(writer: &mut W, value: u64) -> capnp::Result<()> { + write!(writer, "{value}")?; + Ok(()) +} +fn write_signed_number(writer: &mut W, value: i64) -> capnp::Result<()> { + write!(writer, "{value}")?; + Ok(()) +} + +fn write_float_number(writer: &mut W, value: f64) -> capnp::Result<()> { + // From the C++ codec comments: + // Inf, -inf and NaN are not allowed in the JSON spec. Storing into string. + + if value.is_finite() { + write!(writer, "{value}")?; + } else if value.is_nan() { + write_string(writer, "NaN")?; + } else if value.is_infinite() { + if value.is_sign_positive() { + write_string(writer, "Infinity")?; + } else { + write_string(writer, "-Infinity")?; + } + } + Ok(()) +} + +fn write_string(writer: &mut W, value: &str) -> capnp::Result<()> { + write!(writer, "\"")?; + for c in value.chars() { + match c { + '\"' => write!(writer, "\\\"")?, + '\\' => write!(writer, "\\\\")?, + '\n' => write!(writer, "\\n")?, + '\r' => write!(writer, "\\r")?, + '\t' => write!(writer, "\\t")?, + '\u{08}' => write!(writer, "\\b")?, + '\u{0C}' => write!(writer, "\\f")?, + c if c.is_control() => write!(writer, "\\u{:04x}", c as u32)?, + c => write!(writer, "{c}")?, + } + } + write!(writer, "\"")?; + Ok(()) +} + +fn write_array<'reader, W: std::io::Write, I>( + writer: &mut W, + items: I, + meta: &EncodingOptions, +) -> capnp::Result<()> +where + I: Iterator>>, +{ + write!(writer, "[")?; + let mut first = true; + for item in items { + if !first { + write!(writer, ",")?; + } + first = false; + serialize_value_to(writer, item?, meta, &mut true)?; + } + write!(writer, "]")?; + Ok(()) +} + +fn write_object<'reader, W: std::io::Write>( + writer: &mut W, + reader: capnp::dynamic_struct::Reader<'reader>, + meta: &EncodingOptions<'_, '_>, + first: &mut bool, +) -> capnp::Result<()> { + let (flatten, field_prefix) = if let Some(flatten_options) = &meta.flatten { + ( + true, + std::borrow::Cow::Owned(format!( + "{}{}", + meta.prefix, + flatten_options.get_prefix()?.to_str()? + )), + ) + } else { + (false, std::borrow::Cow::Borrowed("")) + }; + + let mut my_first = true; + + let first = if !flatten { + write!(writer, "{{")?; + &mut my_first + } else { + first + }; + for field in reader.get_schema().get_non_union_fields()? { + if !reader.has(field)? { + continue; + } + let field_meta = EncodingOptions::from_field(&field_prefix, &field)?; + if field_meta.flatten.is_none() { + if !*first { + write!(writer, ",")?; + } + *first = false; + write_string( + writer, + format!("{}{}", field_prefix, field_meta.name).as_str(), + )?; + write!(writer, ":")?; + } + let field_value = reader.get(field)?; + serialize_value_to(writer, field_value, &field_meta, first)?; + } + + // Comment copied verbatim from the Cap'n Proto C++ implementation: + // There are two cases of unions: + // * Named unions, which are special cases of named groups. In this case, the union may be + // annotated by annotating the field. In this case, we receive a non-null `discriminator` + // as a constructor parameter, and schemaProto.getAnnotations() must be empty because + // it's not possible to annotate a group's type (because the type is anonymous). + // * Unnamed unions, of which there can only be one in any particular scope. In this case, + // the parent struct type itself is annotated. + // So if we received `null` as the constructor parameter, check for annotations on the struct + // type. + let struct_discriminator = reader + .get_schema() + .get_annotations()? + .iter() + .find(|a| a.get_id() == json_capnp::discriminator::ID) + .and_then(|annotation| { + annotation + .get_value() + .ok() + .map(|v| v.downcast_struct::()) + }); + let discriminator = meta.discriminator.or(struct_discriminator); + + if let Some(active_union_member) = reader.which()? { + let active_union_member_meta = + EncodingOptions::from_field(&field_prefix, &active_union_member)?; + if reader.has(active_union_member)? { + let mut value_name = active_union_member_meta.name; + let mut suppress_void = false; + if let Some(discriminator) = discriminator { + let discriminator_name = if discriminator.has_name() { + Some(discriminator.get_name()?.to_str()?) + } else if flatten { + Some(meta.name) + } else { + // https://github.com/capnproto/capnproto/issues/2461 + // The discriminator is not output even if the annoyation is + // present if: + // - it doesn't have an explicit name, and + // - the group is _not_ being flattened. + None + }; + if discriminator.has_value_name() { + value_name = discriminator.get_value_name()?.to_str()?; + } + + if let Some(discriminator_name) = discriminator_name { + if !*first { + write!(writer, ",")?; + } + *first = false; + suppress_void = true; + write_string( + writer, + format!("{field_prefix}{discriminator_name}").as_str(), + )?; + write!(writer, ":")?; + write_string(writer, active_union_member_meta.name)?; + } + } + let field_value = reader.get(active_union_member)?; + if !suppress_void || !matches!(field_value, capnp::dynamic_value::Reader::Void) { + if active_union_member_meta.flatten.is_none() { + if !*first { + write!(writer, ",")?; + } + *first = false; + write_string(writer, format!("{field_prefix}{value_name}").as_str())?; + write!(writer, ":")?; + } + serialize_value_to(writer, field_value, &active_union_member_meta, first)?; + } + } + } + if !flatten { + write!(writer, "}}")?; + } + Ok(()) +} + +fn write_data( + writer: &mut W, + data: capnp::data::Reader<'_>, + encoding: DataEncoding, +) -> capnp::Result<()> { + match encoding { + DataEncoding::Default => { + write!(writer, "[")?; + let mut first = true; + for byte in data.iter() { + if !first { + write!(writer, ",")?; + } + first = false; + write!(writer, "{byte}")?; + } + write!(writer, "]")?; + Ok(()) + } + DataEncoding::Base64 => write_string(writer, base64::encode(data).as_str()), + DataEncoding::Hex => write_string(writer, hex::encode(data).as_str()), + } +} diff --git a/capnp-json/src/json_capnp.rs b/capnp-json/src/json_capnp.rs new file mode 100644 index 000000000..d1d574aaa --- /dev/null +++ b/capnp-json/src/json_capnp.rs @@ -0,0 +1,2118 @@ +// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler. +// DO NOT EDIT. +// source: json.capnp + +pub mod value { + pub use self::Which::{Array, Boolean, Call, Null, Number, Object, Raw, String}; + + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl ::core::marker::Copy for Reader<'_> {} + impl ::core::clone::Clone for Reader<'_> { + fn clone(&self) -> Self { + *self + } + } + + impl ::capnp::traits::HasTypeId for Reader<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl ::core::fmt::Debug for Reader<'_> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn has_string(&self) -> bool { + if self.reader.get_data_field::(0) != 3 { + return false; + } + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn has_array(&self) -> bool { + if self.reader.get_data_field::(0) != 4 { + return false; + } + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn has_object(&self) -> bool { + if self.reader.get_data_field::(0) != 5 { + return false; + } + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn has_call(&self) -> bool { + if self.reader.get_data_field::(0) != 6 { + return false; + } + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn has_raw(&self) -> bool { + if self.reader.get_data_field::(0) != 7 { + return false; + } + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn which(self) -> ::core::result::Result, ::capnp::NotInSchema> { + match self.reader.get_data_field::(0) { + 0 => ::core::result::Result::Ok(Null(())), + 1 => ::core::result::Result::Ok(Boolean(self.reader.get_bool_field(16))), + 2 => ::core::result::Result::Ok(Number(self.reader.get_data_field::(1))), + 3 => ::core::result::Result::Ok(String( + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 4 => ::core::result::Result::Ok(Array( + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 5 => ::core::result::Result::Ok(Object( + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 6 => ::core::result::Result::Ok(Call( + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 7 => ::core::result::Result::Ok(Raw( + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + x => ::core::result::Result::Err(::capnp::NotInSchema(x)), + } + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl ::capnp::traits::HasStructSize for Builder<'_> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 2, + pointers: 1, + }; + } + impl ::capnp::traits::HasTypeId for Builder<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl ::capnp::traits::SetterInput for Reader<'_> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn set_null(&mut self, _value: ()) { + self.builder.set_data_field::(0, 0); + } + #[inline] + pub fn set_boolean(&mut self, value: bool) { + self.builder.set_data_field::(0, 1); + self.builder.set_bool_field(16, value); + } + #[inline] + pub fn set_number(&mut self, value: f64) { + self.builder.set_data_field::(0, 2); + self.builder.set_data_field::(1, value); + } + #[inline] + pub fn set_string( + &mut self, + value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>, + ) { + self.builder.set_data_field::(0, 3); + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_string(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.set_data_field::(0, 3); + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_string(&self) -> bool { + if self.builder.get_data_field::(0) != 3 { + return false; + } + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn set_array( + &mut self, + value: ::capnp::struct_list::Reader<'_, crate::json_capnp::value::Owned>, + ) -> ::capnp::Result<()> { + self.builder.set_data_field::(0, 4); + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + } + #[inline] + pub fn init_array( + self, + size: u32, + ) -> ::capnp::struct_list::Builder<'a, crate::json_capnp::value::Owned> { + self.builder.set_data_field::(0, 4); + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(0), + size, + ) + } + #[inline] + pub fn has_array(&self) -> bool { + if self.builder.get_data_field::(0) != 4 { + return false; + } + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn set_object( + &mut self, + value: ::capnp::struct_list::Reader<'_, crate::json_capnp::value::field::Owned>, + ) -> ::capnp::Result<()> { + self.builder.set_data_field::(0, 5); + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + } + #[inline] + pub fn init_object( + self, + size: u32, + ) -> ::capnp::struct_list::Builder<'a, crate::json_capnp::value::field::Owned> { + self.builder.set_data_field::(0, 5); + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(0), + size, + ) + } + #[inline] + pub fn has_object(&self) -> bool { + if self.builder.get_data_field::(0) != 5 { + return false; + } + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn set_call( + &mut self, + value: crate::json_capnp::value::call::Reader<'_>, + ) -> ::capnp::Result<()> { + self.builder.set_data_field::(0, 6); + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + } + #[inline] + pub fn init_call(self) -> crate::json_capnp::value::call::Builder<'a> { + self.builder.set_data_field::(0, 6); + ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0) + } + #[inline] + pub fn has_call(&self) -> bool { + if self.builder.get_data_field::(0) != 6 { + return false; + } + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn set_raw(&mut self, value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>) { + self.builder.set_data_field::(0, 7); + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_raw(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.set_data_field::(0, 7); + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_raw(&self) -> bool { + if self.builder.get_data_field::(0) != 7 { + return false; + } + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn which(self) -> ::core::result::Result, ::capnp::NotInSchema> { + match self.builder.get_data_field::(0) { + 0 => ::core::result::Result::Ok(Null(())), + 1 => ::core::result::Result::Ok(Boolean(self.builder.get_bool_field(16))), + 2 => ::core::result::Result::Ok(Number(self.builder.get_data_field::(1))), + 3 => ::core::result::Result::Ok(String( + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 4 => ::core::result::Result::Ok(Array( + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 5 => ::core::result::Result::Ok(Object( + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 6 => ::core::result::Result::Ok(Call( + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + 7 => ::core::result::Result::Ok(Raw( + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ), + )), + x => ::core::result::Result::Err(::capnp::NotInSchema(x)), + } + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 152] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(131, 221, 25, 249, 69, 120, 250, 163), + ::capnp::word(11, 0, 0, 0, 1, 0, 2, 0), + ::capnp::word(52, 94, 58, 164, 151, 146, 249, 142), + ::capnp::word(1, 0, 7, 0, 0, 0, 8, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(216, 4, 0, 0, 47, 11, 0, 0), + ::capnp::word(21, 0, 0, 0, 138, 0, 0, 0), + ::capnp::word(29, 0, 0, 0, 39, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(49, 0, 0, 0, 199, 1, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(106, 115, 111, 110, 46, 99, 97, 112), + ::capnp::word(110, 112, 58, 86, 97, 108, 117, 101), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(8, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(223, 157, 214, 53, 231, 38, 16, 227), + ::capnp::word(9, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(72, 61, 201, 161, 236, 246, 217, 160), + ::capnp::word(5, 0, 0, 0, 42, 0, 0, 0), + ::capnp::word(70, 105, 101, 108, 100, 0, 0, 0), + ::capnp::word(67, 97, 108, 108, 0, 0, 0, 0), + ::capnp::word(32, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 255, 255, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(209, 0, 0, 0, 42, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(204, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(216, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 254, 255, 16, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(213, 0, 0, 0, 66, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(208, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(220, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(2, 0, 253, 255, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(217, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(212, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(224, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(3, 0, 252, 255, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 3, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(221, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(216, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(228, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(4, 0, 251, 255, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 4, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(225, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(220, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(248, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(5, 0, 250, 255, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 5, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(245, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(240, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(6, 0, 249, 255, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 6, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(9, 1, 0, 0, 42, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(4, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(7, 0, 248, 255, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(13, 1, 0, 0, 34, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(8, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(20, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(110, 117, 108, 108, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(98, 111, 111, 108, 101, 97, 110, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(110, 117, 109, 98, 101, 114, 0, 0), + ::capnp::word(11, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(11, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 116, 114, 105, 110, 103, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(97, 114, 114, 97, 121, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(131, 221, 25, 249, 69, 120, 250, 163), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(111, 98, 106, 101, 99, 116, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(223, 157, 214, 53, 231, 38, 16, 227), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(99, 97, 108, 108, 0, 0, 0, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(72, 61, 201, 161, 236, 246, 217, 160), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(114, 97, 119, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <() as ::capnp::introspect::Introspect>::introspect(), + 1 => ::introspect(), + 2 => ::introspect(), + 3 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 4 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 5 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 6 => ::introspect(), + 7 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => ::capnp::introspect::panic_invalid_field_index(index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + members_by_name: MEMBERS_BY_NAME, + }; + pub static NONUNION_MEMBERS: &[u16] = &[]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[0, 1, 2, 3, 4, 5, 6, 7]; + pub static MEMBERS_BY_NAME: &[u16] = &[4, 1, 6, 0, 2, 5, 7, 3]; + pub const TYPE_ID: u64 = 0xa3fa_7845_f919_dd83; + } + pub enum Which { + Null(()), + Boolean(bool), + Number(f64), + String(A0), + Array(A1), + Object(A2), + Call(A3), + Raw(A4), + } + pub type WhichReader<'a> = Which< + ::capnp::Result<::capnp::text::Reader<'a>>, + ::capnp::Result<::capnp::struct_list::Reader<'a, crate::json_capnp::value::Owned>>, + ::capnp::Result<::capnp::struct_list::Reader<'a, crate::json_capnp::value::field::Owned>>, + ::capnp::Result>, + ::capnp::Result<::capnp::text::Reader<'a>>, + >; + pub type WhichBuilder<'a> = Which< + ::capnp::Result<::capnp::text::Builder<'a>>, + ::capnp::Result<::capnp::struct_list::Builder<'a, crate::json_capnp::value::Owned>>, + ::capnp::Result<::capnp::struct_list::Builder<'a, crate::json_capnp::value::field::Owned>>, + ::capnp::Result>, + ::capnp::Result<::capnp::text::Builder<'a>>, + >; + + pub mod field { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl ::core::marker::Copy for Reader<'_> {} + impl ::core::clone::Clone for Reader<'_> { + fn clone(&self) -> Self { + *self + } + } + + impl ::capnp::traits::HasTypeId for Reader<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl ::core::fmt::Debug for Reader<'_> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_name(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_value(self) -> ::capnp::Result> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_value(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl ::capnp::traits::HasStructSize for Builder<'_> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 2, + }; + } + impl ::capnp::traits::HasTypeId for Builder<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + _size: u32, + ) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl ::capnp::traits::SetterInput for Reader<'_> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_name( + &mut self, + value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>, + ) { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_name(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_value(self) -> ::capnp::Result> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_value( + &mut self, + value: crate::json_capnp::value::Reader<'_>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(1), + value, + false, + ) + } + #[inline] + pub fn init_value(self) -> crate::json_capnp::value::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(1), + 0, + ) + } + #[inline] + pub fn has_value(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline { + pub fn get_value(&self) -> crate::json_capnp::value::Pipeline { + ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(1)) + } + } + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 48] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(223, 157, 214, 53, 231, 38, 16, 227), + ::capnp::word(17, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(131, 221, 25, 249, 69, 120, 250, 163), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(171, 10, 0, 0, 229, 10, 0, 0), + ::capnp::word(21, 0, 0, 0, 186, 0, 0, 0), + ::capnp::word(29, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(25, 0, 0, 0, 119, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(106, 115, 111, 110, 46, 99, 97, 112), + ::capnp::word(110, 112, 58, 86, 97, 108, 117, 101), + ::capnp::word(46, 70, 105, 101, 108, 100, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 42, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(36, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(48, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(52, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(110, 97, 109, 101, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(118, 97, 108, 117, 101, 0, 0, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(131, 221, 25, 249, 69, 120, 250, 163), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => ::introspect(), + _ => ::capnp::introspect::panic_invalid_field_index(index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + members_by_name: MEMBERS_BY_NAME, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub static MEMBERS_BY_NAME: &[u16] = &[0, 1]; + pub const TYPE_ID: u64 = 0xe310_26e7_35d6_9ddf; + } + } + + pub mod call { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl ::core::marker::Copy for Reader<'_> {} + impl ::core::clone::Clone for Reader<'_> { + fn clone(&self) -> Self { + *self + } + } + + impl ::capnp::traits::HasTypeId for Reader<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl ::core::fmt::Debug for Reader<'_> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_function(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_function(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_params( + self, + ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, crate::json_capnp::value::Owned>> + { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_params(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl ::capnp::traits::HasStructSize for Builder<'_> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 2, + }; + } + impl ::capnp::traits::HasTypeId for Builder<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + _size: u32, + ) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl ::capnp::traits::SetterInput for Reader<'_> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_function(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_function( + &mut self, + value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>, + ) { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_function(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_function(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_params( + self, + ) -> ::capnp::Result<::capnp::struct_list::Builder<'a, crate::json_capnp::value::Owned>> + { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_params( + &mut self, + value: ::capnp::struct_list::Reader<'_, crate::json_capnp::value::Owned>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(1), + value, + false, + ) + } + #[inline] + pub fn init_params( + self, + size: u32, + ) -> ::capnp::struct_list::Builder<'a, crate::json_capnp::value::Owned> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(1), + size, + ) + } + #[inline] + pub fn has_params(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 53] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(72, 61, 201, 161, 236, 246, 217, 160), + ::capnp::word(17, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(131, 221, 25, 249, 69, 120, 250, 163), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(233, 10, 0, 0, 45, 11, 0, 0), + ::capnp::word(21, 0, 0, 0, 178, 0, 0, 0), + ::capnp::word(29, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(25, 0, 0, 0, 119, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(106, 115, 111, 110, 46, 99, 97, 112), + ::capnp::word(110, 112, 58, 86, 97, 108, 117, 101), + ::capnp::word(46, 67, 97, 108, 108, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 74, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(52, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(49, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(44, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(72, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(102, 117, 110, 99, 116, 105, 111, 110), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(112, 97, 114, 97, 109, 115, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(131, 221, 25, 249, 69, 120, 250, 163), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => ::capnp::introspect::panic_invalid_field_index(index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + members_by_name: MEMBERS_BY_NAME, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub static MEMBERS_BY_NAME: &[u16] = &[0, 1]; + pub const TYPE_ID: u64 = 0xa0d9_f6ec_a1c9_3d48; + } + } +} +pub mod name { + pub const ID: u64 = 0xfa5b1fd61c2e7c3d; + pub fn get_type() -> ::capnp::introspect::Type { + <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect() + } +} +pub mod flatten { + pub const ID: u64 = 0x82d3e852af0336bf; + pub fn get_type() -> ::capnp::introspect::Type { + ::introspect() + } +} + +pub mod flatten_options { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl ::core::marker::Copy for Reader<'_> {} + impl ::core::clone::Clone for Reader<'_> { + fn clone(&self) -> Self { + *self + } + } + + impl ::capnp::traits::HasTypeId for Reader<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl ::core::fmt::Debug for Reader<'_> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_prefix(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::Some(&_private::DEFAULT_PREFIX[..]), + ) + } + #[inline] + pub fn has_prefix(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl ::capnp::traits::HasStructSize for Builder<'_> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 1, + }; + } + impl ::capnp::traits::HasTypeId for Builder<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl ::capnp::traits::SetterInput for Reader<'_> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_prefix(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::Some(&_private::DEFAULT_PREFIX[..]), + ) + } + #[inline] + pub fn set_prefix( + &mut self, + value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>, + ) { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_prefix(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_prefix(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 35] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(97, 234, 194, 123, 37, 19, 223, 196), + ::capnp::word(11, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(52, 94, 58, 164, 151, 146, 249, 142), + ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(180, 15, 0, 0, 35, 16, 0, 0), + ::capnp::word(21, 0, 0, 0, 210, 0, 0, 0), + ::capnp::word(33, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(29, 0, 0, 0, 63, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(106, 115, 111, 110, 46, 99, 97, 112), + ::capnp::word(110, 112, 58, 70, 108, 97, 116, 116), + ::capnp::word(101, 110, 79, 112, 116, 105, 111, 110), + ::capnp::word(115, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(4, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(13, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(20, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(112, 114, 101, 102, 105, 120, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 10, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => ::capnp::introspect::panic_invalid_field_index(index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + members_by_name: MEMBERS_BY_NAME, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub static MEMBERS_BY_NAME: &[u16] = &[0]; + pub static DEFAULT_PREFIX: [::capnp::Word; 2] = [ + ::capnp::word(1, 0, 0, 0, 10, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub const TYPE_ID: u64 = 0xc4df_1325_7bc2_ea61; + } +} +pub mod discriminator { + pub const ID: u64 = 0xcfa794e8d19a0162; + pub fn get_type() -> ::capnp::introspect::Type { + ::introspect() + } +} + +pub mod discriminator_options { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl ::core::marker::Copy for Reader<'_> {} + impl ::core::clone::Clone for Reader<'_> { + fn clone(&self) -> Self { + *self + } + } + + impl ::capnp::traits::HasTypeId for Reader<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl ::core::fmt::Debug for Reader<'_> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_name(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_value_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_value_name(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl ::capnp::traits::HasStructSize for Builder<'_> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 2, + }; + } + impl ::capnp::traits::HasTypeId for Builder<'_> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl ::capnp::traits::SetterInput for Reader<'_> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_name(&mut self, value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>) { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_name(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_value_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_value_name( + &mut self, + value: impl ::capnp::traits::SetterInput<::capnp::text::Owned>, + ) { + ::capnp::traits::SetterInput::set_pointer_builder( + self.builder.reborrow().get_pointer_field(1), + value, + false, + ) + .unwrap() + } + #[inline] + pub fn init_value_name(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(1).init_text(size) + } + #[inline] + pub fn has_value_name(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 50] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(25, 83, 62, 41, 12, 194, 248, 194), + ::capnp::word(11, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(52, 94, 58, 164, 151, 146, 249, 142), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(187, 17, 0, 0, 184, 19, 0, 0), + ::capnp::word(21, 0, 0, 0, 2, 1, 0, 0), + ::capnp::word(33, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(29, 0, 0, 0, 119, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(106, 115, 111, 110, 46, 99, 97, 112), + ::capnp::word(110, 112, 58, 68, 105, 115, 99, 114), + ::capnp::word(105, 109, 105, 110, 97, 116, 111, 114), + ::capnp::word(79, 112, 116, 105, 111, 110, 115, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 42, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(36, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(48, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 0, 0, 0, 82, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(44, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(56, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(110, 97, 109, 101, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(118, 97, 108, 117, 101, 78, 97, 109), + ::capnp::word(101, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => ::capnp::introspect::panic_invalid_field_index(index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + ::capnp::introspect::panic_invalid_annotation_indices(child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + members_by_name: MEMBERS_BY_NAME, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub static MEMBERS_BY_NAME: &[u16] = &[0, 1]; + pub const TYPE_ID: u64 = 0xc2f8_c20c_293e_5319; + } +} +pub mod base64 { + pub const ID: u64 = 0xd7d879450a253e4b; + pub fn get_type() -> ::capnp::introspect::Type { + <() as ::capnp::introspect::Introspect>::introspect() + } +} +pub mod hex { + pub const ID: u64 = 0xf061e22f0ae5c7b5; + pub fn get_type() -> ::capnp::introspect::Type { + <() as ::capnp::introspect::Introspect>::introspect() + } +} +pub mod notification { + pub const ID: u64 = 0xa0a054dea32fd98c; + pub fn get_type() -> ::capnp::introspect::Type { + <() as ::capnp::introspect::Introspect>::introspect() + } +} diff --git a/capnp-json/src/lib.rs b/capnp-json/src/lib.rs new file mode 100644 index 000000000..7d128dfd2 --- /dev/null +++ b/capnp-json/src/lib.rs @@ -0,0 +1,112 @@ +mod data; +mod decode; +mod encode; + +pub mod json_capnp; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +enum DataEncoding { + #[default] + Default, + Base64, + Hex, +} + +#[derive(Debug)] +struct EncodingOptions<'schema, 'prefix> { + prefix: &'prefix std::borrow::Cow<'schema, str>, + name: &'schema str, + flatten: Option>, + discriminator: Option>, + data_encoding: DataEncoding, +} + +impl<'schema, 'prefix> EncodingOptions<'schema, 'prefix> { + fn from_field( + prefix: &'prefix std::borrow::Cow<'schema, str>, + field: &capnp::schema::Field, + ) -> capnp::Result { + let mut options = Self { + prefix, + name: field.get_proto().get_name()?.to_str()?, + flatten: None, + discriminator: None, + data_encoding: DataEncoding::Default, + }; + + for anno in field.get_annotations()?.iter() { + match anno.get_id() { + json_capnp::name::ID => { + options.name = anno + .get_value()? + .downcast::() + .to_str()?; + } + json_capnp::base64::ID => { + if options.data_encoding != DataEncoding::Default { + return Err(capnp::Error::failed( + "Cannot specify both base64 and hex annotations on the same field" + .into(), + )); + } + options.data_encoding = DataEncoding::Base64; + } + json_capnp::hex::ID => { + if options.data_encoding != DataEncoding::Default { + return Err(capnp::Error::failed( + "Cannot specify both base64 and hex annotations on the same field" + .into(), + )); + } + options.data_encoding = DataEncoding::Hex; + } + json_capnp::flatten::ID => { + options.flatten = Some( + anno.get_value()? + .downcast_struct::(), + ); + } + json_capnp::discriminator::ID => { + options.discriminator = Some( + anno.get_value()? + .downcast_struct::(), + ); + } + _ => {} + } + } + if options.data_encoding != DataEncoding::Default { + let mut element_type = field.get_type(); + while let capnp::introspect::TypeVariant::List(sub_element_type) = element_type.which() + { + element_type = sub_element_type; + } + if !matches!(element_type.which(), capnp::introspect::TypeVariant::Data) { + return Err(capnp::Error::failed( + "base64/hex annotation can only be applied to Data fields".into(), + )); + } + } + Ok(options) + } +} + +pub fn to_json<'reader>( + reader: impl Into>, +) -> capnp::Result { + let mut writer = std::io::Cursor::new(Vec::with_capacity(4096)); + encode::serialize_json_to(&mut writer, reader)?; + String::from_utf8(writer.into_inner()).map_err(|e| e.into()) +} + +pub fn from_json<'segments>( + json: &str, + builder: impl Into>, +) -> capnp::Result<()> { + let capnp::dynamic_value::Builder::Struct(builder) = builder.into() else { + return Err(capnp::Error::failed( + "Top-level JSON value must be an object".into(), + )); + }; + decode::parse(json, builder) +} diff --git a/capnp-json/test/Cargo.toml b/capnp-json/test/Cargo.toml new file mode 100644 index 000000000..ed3fa9bd4 --- /dev/null +++ b/capnp-json/test/Cargo.toml @@ -0,0 +1,26 @@ +[package] + +name = "capnp-json-test" +version = "0.0.0" +authors = [ "David Renshaw ", "Ben Jackson " ] +build = "build.rs" +edition = "2021" + +[lib] +name = "capnp_json_test" +path = "json.rs" + +[build-dependencies] +capnpc = { path = "../../capnpc" } + +[dependencies] +capnp = { path = "../../capnp" } +capnpc = { path = "../../capnpc" } +capnp-json = { path = "../" } +external-crate = { path = "../../capnpc/test/external-crate" } + +[lints.clippy] +type_complexity = "allow" +extra_unused_type_parameters = "allow" +match_single_binding = "allow" +approx_constant = "allow" diff --git a/capnp-json/test/build.rs b/capnp-json/test/build.rs new file mode 100644 index 000000000..2a2e39e8c --- /dev/null +++ b/capnp-json/test/build.rs @@ -0,0 +1,8 @@ +fn main() { + capnpc::CompilerCommand::new() + .crate_provides("capnp_json", [0x8ef99297a43a5e34]) // json.capnp + .file("test.capnp") + .file("json-test.capnp") + .run() + .expect("compiling schema"); +} diff --git a/capnp-json/test/cppcompat.rs b/capnp-json/test/cppcompat.rs new file mode 100644 index 000000000..b28820759 --- /dev/null +++ b/capnp-json/test/cppcompat.rs @@ -0,0 +1,366 @@ +#[cfg(test)] +mod tests { + use crate::json_test_capnp::test_json_annotations; + use std::io::Write; + + use capnp::message; + + fn cpp_binary_to_json(proto: &str, kind: &str, data: &[u8]) -> capnp::Result { + let output = std::process::Command::new("capnp") + .args(["convert", "binary:json", proto, kind]) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .and_then(|child| { + child.stdin.as_ref().map(|mut stdin| stdin.write_all(data)); + child.wait_with_output() + })?; + String::from_utf8(output.stdout).map_err(|e| e.into()) + } + + fn cpp_json_to_binary(proto: &str, kind: &str, data: &[u8]) -> capnp::Result> { + let output = std::process::Command::new("capnp") + .args(["convert", "json:binary", proto, kind]) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .and_then(|child| { + child.stdin.as_ref().map(|mut stdin| stdin.write_all(data)); + child.wait_with_output() + })?; + Ok(output.stdout) + } + + fn make_test_message( + builder: &mut message::Builder, + ) -> capnp::Result> { + let mut root: test_json_annotations::Builder<'_> = builder.init_root(); + + root.set_some_field("Some Field"); + { + let mut a_group = root.reborrow().init_a_group(); + // a_group is flattenned + a_group.set_flat_foo(0xF00); + a_group.set_flat_bar("0xBaa"); + a_group.reborrow().init_flat_baz().set_hello(true); + a_group.reborrow().init_double_flat().set_flat_qux("Qux"); + } + + { + let mut prefixed_group = root.reborrow().init_prefixed_group(); + prefixed_group.set_foo("Foo"); + prefixed_group.set_bar(0xBAA); + prefixed_group.reborrow().init_baz().set_hello(false); + prefixed_group.reborrow().init_more_prefix().set_qux("Qux"); + } + + { + let mut a_union_bar = root.reborrow().init_a_union().init_bar(); + a_union_bar.set_bar_member(0xAAB); + a_union_bar.set_multi_member("Member"); + } + + { + let mut dependency = root.reborrow().init_dependency(); + dependency.set_foo("dep-foo"); + } + + { + let mut simple_group = root.reborrow().init_simple_group(); + simple_group.set_grault("grault"); + } + + { + let mut e = root.reborrow().init_enums(4); + e.set(0, crate::json_test_capnp::TestJsonAnnotatedEnum::Foo); + e.set(1, crate::json_test_capnp::TestJsonAnnotatedEnum::Bar); + e.set(2, crate::json_test_capnp::TestJsonAnnotatedEnum::Baz); + e.set(3, crate::json_test_capnp::TestJsonAnnotatedEnum::Qux); + } + + { + let mut b_union = root.reborrow().init_b_union(); + b_union.set_bar(100); + } + + { + let mut external_union = root.reborrow().init_external_union(); + external_union.reborrow().init_bar().set_value("Value"); + } + + { + let mut union_with_void = root.reborrow().init_union_with_void(); + union_with_void.set_void_value(()); + } + + Ok(root) + } + + fn check_test_message(reader: test_json_annotations::Reader<'_>) -> capnp::Result<()> { + assert_eq!(reader.get_some_field()?, "Some Field"); + + { + let a_group = reader.get_a_group(); + assert_eq!(a_group.get_flat_foo(), 0xF00); + assert_eq!(a_group.get_flat_bar()?, "0xBaa"); + assert!(a_group.get_flat_baz().get_hello()); + assert_eq!(a_group.get_double_flat().get_flat_qux()?, "Qux"); + } + + { + let prefixed_group = reader.get_prefixed_group(); + assert_eq!(prefixed_group.get_foo()?, "Foo"); + assert_eq!(prefixed_group.get_bar(), 0xBAA); + assert!(!prefixed_group.get_baz().get_hello()); + assert_eq!(prefixed_group.get_more_prefix().get_qux()?, "Qux"); + } + + { + let a_union = reader.get_a_union(); + match a_union.which()? { + crate::json_test_capnp::test_json_annotations::a_union::Bar(bar) => { + assert_eq!(bar.get_bar_member(), 0xAAB); + assert_eq!(bar.get_multi_member()?, "Member"); + } + _ => panic!("Expected Bar variant"), + } + } + + { + let dependency = reader.get_dependency()?; + assert_eq!(dependency.get_foo()?, "dep-foo"); + } + + { + let simple_group = reader.get_simple_group(); + assert_eq!(simple_group.get_grault()?, "grault"); + } + + { + let enums = reader.get_enums()?; + assert_eq!(enums.len(), 4); + assert_eq!( + enums.get(0)?, + crate::json_test_capnp::TestJsonAnnotatedEnum::Foo + ); + assert_eq!( + enums.get(1)?, + crate::json_test_capnp::TestJsonAnnotatedEnum::Bar + ); + assert_eq!( + enums.get(2)?, + crate::json_test_capnp::TestJsonAnnotatedEnum::Baz + ); + assert_eq!( + enums.get(3)?, + crate::json_test_capnp::TestJsonAnnotatedEnum::Qux + ); + } + + { + let b_union = reader.get_b_union(); + match b_union.which()? { + crate::json_test_capnp::test_json_annotations::b_union::Bar(value) => { + assert_eq!(value, 100); + } + _ => panic!("Expected Bar variant"), + } + } + + { + let external_union = reader.get_external_union()?; + match external_union.which()? { + crate::json_test_capnp::test_json_annotations3::Bar(bar) => { + assert_eq!(bar?.get_value()?, "Value"); + } + _ => panic!("Expected Bar variant"), + } + } + + { + let union_with_void = reader.get_union_with_void(); + match union_with_void.which()? { + crate::json_test_capnp::test_json_annotations::union_with_void::VoidValue(()) => { + // ok + } + _ => panic!("Expected VoidValue variant"), + } + } + Ok(()) + } + + #[test] + fn read_json_from_cpp_encoder() -> capnp::Result<()> { + let mut builder = message::Builder::new_default(); + make_test_message(&mut builder)?; + let mut buf = vec![]; + capnp::serialize::write_message(&mut buf, &builder)?; + let cpp_json = cpp_binary_to_json("./json-test.capnp", "TestJsonAnnotations", &buf)?; + + let mut buidler = message::Builder::new_default(); + let mut root = buidler.init_root::>(); + eprintln!("CPP generated JSON: {}", cpp_json); + capnp_json::from_json(&cpp_json, root.reborrow())?; + + check_test_message(root.into_reader()) + } + + #[test] + fn write_json_to_cpp() -> capnp::Result<()> { + let mut builder = message::Builder::new_default(); + let root = make_test_message(&mut builder)?; + let json = capnp_json::to_json(root.into_reader())?; + eprintln!("Generated JSON: {}", json); + let cpp_binary = + cpp_json_to_binary("./json-test.capnp", "TestJsonAnnotations", json.as_bytes())?; + let mut cpp_binary = cpp_binary.as_slice(); + + let msg = capnp::serialize::read_message_from_flat_slice( + &mut cpp_binary, + capnp::message::ReaderOptions::default(), + )?; + + check_test_message(msg.get_root::>()?) + } + + #[test] + fn roundtrip_unnamed_discriminator() -> capnp::Result<()> { + let mut builder = message::Builder::new_default(); + let mut root = + builder.init_root::(); + root.reborrow().init_baz().set_bar(100); + root.reborrow().init_sbaz().set_sfoo("Hello"); + + let rust_json = capnp_json::to_json(root.reborrow_as_reader())?; + eprintln!("unnamed_discriminator Generated JSON: {}", rust_json); + + let mut buf = vec![]; + capnp::serialize::write_message(&mut buf, &builder)?; + + let cpp_json = cpp_binary_to_json("./json-test.capnp", "UnnamedDiscriminator", &buf)?; + eprintln!("unnamed_discriminator CPP generated JSON: {}", cpp_json); + + let mut read_json_builder = message::Builder::new_default(); + let mut read_json_root = + read_json_builder.init_root::(); + capnp_json::from_json(&cpp_json, read_json_root.reborrow())?; + let read_json_root = read_json_root.into_reader(); + + assert_eq!( + 100, + match read_json_root.get_baz().which()? { + crate::json_test_capnp::unnamed_discriminator::baz::Bar(bar) => bar, + _ => panic!("Expected Bar variant"), + }, + ); + assert_eq!( + "Hello", + match read_json_root.get_sbaz().which()? { + crate::json_test_capnp::unnamed_discriminator::sbaz::Sfoo(sfoo) => + sfoo?.to_str()?, + _ => panic!("Expected SFoo variant"), + }, + ); + + let cpp_binary = cpp_json_to_binary( + "./json-test.capnp", + "UnnamedDiscriminator", + rust_json.as_bytes(), + )?; + let mut cpp_binary = cpp_binary.as_slice(); + + let read_binary = capnp::serialize::read_message_from_flat_slice( + &mut cpp_binary, + capnp::message::ReaderOptions::default(), + )?; + let read_binary_root = + read_binary.get_root::>()?; + + assert_eq!( + 100, + match read_binary_root.get_baz().which()? { + crate::json_test_capnp::unnamed_discriminator::baz::Bar(bar) => bar, + _ => panic!("Expected Bar variant"), + }, + ); + assert_eq!( + "Hello", + match read_binary_root.get_sbaz().which()? { + crate::json_test_capnp::unnamed_discriminator::sbaz::Sfoo(sfoo) => + sfoo?.to_str()?, + _ => panic!("Expected SFoo variant"), + }, + ); + + Ok(()) + } + + #[test] + fn roundtrip_named_discriminator() -> capnp::Result<()> { + let mut builder = message::Builder::new_default(); + let mut root = builder.init_root::(); + root.reborrow().init_baz().set_bar(100); + root.reborrow().init_sbaz().set_sfoo("Hello"); + + let rust_json = capnp_json::to_json(root.reborrow_as_reader())?; + eprintln!("named_discriminator Generated JSON: {}", rust_json); + + let mut buf = vec![]; + capnp::serialize::write_message(&mut buf, &builder)?; + + let cpp_json = cpp_binary_to_json("./json-test.capnp", "NamedDiscriminator", &buf)?; + eprintln!("named_discriminator CPP generated JSON: {}", cpp_json); + + let mut read_json_builder = message::Builder::new_default(); + let mut read_json_root = + read_json_builder.init_root::(); + capnp_json::from_json(&cpp_json, read_json_root.reborrow())?; + let read_json_root = read_json_root.into_reader(); + + assert_eq!( + 100, + match read_json_root.get_baz().which()? { + crate::json_test_capnp::named_discriminator::baz::Bar(bar) => bar, + _ => panic!("Expected Bar variant"), + }, + ); + assert_eq!( + "Hello", + match read_json_root.get_sbaz().which()? { + crate::json_test_capnp::named_discriminator::sbaz::Sfoo(sfoo) => sfoo?.to_str()?, + _ => panic!("Expected SFoo variant"), + }, + ); + + let cpp_binary = cpp_json_to_binary( + "./json-test.capnp", + "NamedDiscriminator", + rust_json.as_bytes(), + )?; + let mut cpp_binary = cpp_binary.as_slice(); + + let read_binary = capnp::serialize::read_message_from_flat_slice( + &mut cpp_binary, + capnp::message::ReaderOptions::default(), + )?; + let read_binary_root = + read_binary.get_root::>()?; + + assert_eq!( + 100, + match read_binary_root.get_baz().which()? { + crate::json_test_capnp::named_discriminator::baz::Bar(bar) => bar, + _ => panic!("Expected Bar variant"), + }, + ); + assert_eq!( + "Hello", + match read_binary_root.get_sbaz().which()? { + crate::json_test_capnp::named_discriminator::sbaz::Sfoo(sfoo) => sfoo?.to_str()?, + _ => panic!("Expected SFoo variant"), + }, + ); + + Ok(()) + } +} diff --git a/capnp-json/test/json-test.capnp b/capnp-json/test/json-test.capnp new file mode 100644 index 000000000..1455d8b83 --- /dev/null +++ b/capnp-json/test/json-test.capnp @@ -0,0 +1,158 @@ +# Copyright (c) 2018 Cloudflare, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xc9d405cf4333e4c9; + +using Json = import "/capnp/compat/json.capnp"; + +$import "/capnp/c++.capnp".namespace("capnp"); + +struct TestJsonAnnotations { + someField @0 :Text $Json.name("names-can_contain!anything Really"); + + aGroup :group $Json.flatten() { + flatFoo @1 :UInt32; + flatBar @2 :Text; + flatBaz :group $Json.name("renamed-flatBaz") { + hello @3 :Bool; + } + doubleFlat :group $Json.flatten() { + flatQux @4 :Text; + } + } + + prefixedGroup :group $Json.flatten(prefix = "pfx.") { + foo @5 :Text; + bar @6 :UInt32 $Json.name("renamed-bar"); + baz :group { + hello @7 :Bool; + } + morePrefix :group $Json.flatten(prefix = "xfp.") { + qux @8 :Text; + } + } + + aUnion :union $Json.flatten() $Json.discriminator(name = "union-type") { + foo :group $Json.flatten() { + fooMember @9 :Text; + multiMember @10 :UInt32; + } + bar :group $Json.flatten() $Json.name("renamed-bar") { + barMember @11 :UInt32; + multiMember @12 :Text; + } + } + + dependency @13 :TestJsonAnnotations2; + # To test that dependencies are loaded even if not flattened. + + simpleGroup :group { + # To test that group types are loaded even if not flattened. + grault @14 :Text $Json.name("renamed-grault"); + } + + enums @15 :List(TestJsonAnnotatedEnum); + + innerJson @16 :Json.Value; + + customFieldHandler @17 :Text; + + testBase64 @18 :Data $Json.base64; + testHex @19 :Data $Json.hex; + + bUnion :union $Json.flatten() $Json.discriminator(valueName = "bValue") { + foo @20 :Text; + bar @21 :UInt32 $Json.name("renamed-bar"); + } + + externalUnion @22 :TestJsonAnnotations3; + + unionWithVoid :union $Json.discriminator(name = "type") { + intValue @23 :UInt32; + voidValue @24 :Void; + textValue @25 :Text; + } +} + +struct TestJsonAnnotations2 { + foo @0 :Text $Json.name("renamed-foo"); + cycle @1 :TestJsonAnnotations; +} + +struct TestJsonAnnotations3 $Json.discriminator(name = "type") { + union { + foo @0 :UInt32; + bar @1 :TestFlattenedStruct $Json.flatten(); + } +} + +struct TestFlattenedStruct { + value @0 :Text; +} + +enum TestJsonAnnotatedEnum { + foo @0; + bar @1 $Json.name("renamed-bar"); + baz @2 $Json.name("renamed-baz"); + qux @3; +} + +struct TestBase64Union { + union { + foo @0 :Data $Json.base64; + bar @1 :Text; + } +} + +struct TestRenamedAnonUnion { + union { + foo @0 :Data $Json.base64 $Json.name("renamed-foo"); + bar @1 :Text; + } +} + +struct NestedHex { + dataAllTheWayDown @0 : List(List(Data)) $Json.hex; +} + +struct UnnamedDiscriminator { + baz: union $Json.discriminator() { + foo @0 :Text; + bar @1 :UInt32; + } + + sbaz: union $Json.discriminator() $Json.flatten() { + sfoo @2 :Text; + sbar @3 :UInt32; + } +} + +struct NamedDiscriminator { + baz: union $Json.discriminator(name="baz_kind") { + foo @0 :Text; + bar @1 :UInt32; + } + + sbaz: union $Json.discriminator(name="sbaz_kind") $Json.flatten() { + sfoo @2 :Text; + sbar @3 :UInt32; + } +} diff --git a/capnp-json/test/json.rs b/capnp-json/test/json.rs new file mode 100644 index 000000000..e1166f6c9 --- /dev/null +++ b/capnp-json/test/json.rs @@ -0,0 +1,807 @@ +// Copyright (c) 2025 Ben Jackson [puremourning@gmail.com] and Cap'n Proto contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +capnp::generated_code!(pub mod test_capnp); +capnp::generated_code!(pub mod json_test_capnp); + +mod cppcompat; + +#[cfg(test)] +mod tests { + use crate::json_test_capnp::test_json_annotations; + use crate::test_capnp::{ + test_json_flatten_union, test_json_types, test_union, test_unnamed_union, TestEnum, + }; + use capnp::message; + use capnp_json as json; + + #[test] + fn test_encode_json_types_default() { + let mut builder = message::Builder::new_default(); + let root: test_json_types::Builder<'_> = builder.init_root(); + let expected = r#"{"voidField":null,"boolField":false,"int8Field":0,"int16Field":0,"int32Field":0,"int64Field":0,"uInt8Field":0,"uInt16Field":0,"uInt32Field":0,"uInt64Field":0,"float32Field":0,"float64Field":0,"enumField":"foo"}"#; + assert_eq!(expected, json::to_json(root.reborrow_as_reader()).unwrap()); + } + + #[test] + fn test_encode_all_json_types() { + let mut builder = message::Builder::new_default(); + let mut root: test_json_types::Builder<'_> = builder.init_root(); + root.set_int8_field(-8); + root.set_int16_field(-16); + root.set_int32_field(-32); + root.set_int64_field(-64); + root.set_u_int8_field(8); + root.set_u_int16_field(16); + root.set_u_int32_field(32); + root.set_u_int64_field(64); + root.set_bool_field(true); + root.set_void_field(()); + root.set_text_field("hello"); + root.set_float32_field(1.32); + root.set_float64_field(1.64); + root.set_data_field(&[0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe]); + root.set_base64_field(&[0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe]); + root.set_hex_field(&[0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe]); + { + let mut embedded = root.reborrow().init_struct_field(); + let mut text_list = embedded.reborrow().init_text_list(2); + text_list.set(0, "frist"); + text_list.set(1, "segund"); + embedded.set_text_field("inner"); + let mut hex_list = embedded.reborrow().init_hex_list(2); + hex_list.set(0, &[0xde, 0xad, 0xbe, 0xef]); + hex_list.set(1, &[0xba, 0xdf, 0x00, 0xd0]); + let mut based_list = embedded.reborrow().init_base64_list(2); + based_list.set(0, &[0xde, 0xad, 0xbe, 0xef]); + based_list.set(1, &[0xba, 0xdf, 0x00, 0xd0]); + } + root.set_enum_field(TestEnum::Quux); + { + let mut enum_list = root.reborrow().init_enum_list(3); + enum_list.set(0, TestEnum::Foo); + enum_list.set(1, TestEnum::Bar); + enum_list.set(2, TestEnum::Garply); + } + { + let mut floats = root.reborrow().init_float32_list(3); + floats.set(0, f32::NAN); + floats.set(1, f32::INFINITY); + floats.set(2, f32::NEG_INFINITY); + } + { + let mut floats = root.reborrow().init_float64_list(3); + floats.set(0, f64::NAN); + floats.set(1, f64::INFINITY); + floats.set(2, f64::NEG_INFINITY); + } + + let expected = concat!( + "{", + r#""voidField":null,"#, + r#""boolField":true,"#, + r#""int8Field":-8,"#, + r#""int16Field":-16,"#, + r#""int32Field":-32,"#, + r#""int64Field":-64,"#, + r#""uInt8Field":8,"#, + r#""uInt16Field":16,"#, + r#""uInt32Field":32,"#, + r#""uInt64Field":64,"#, + r#""float32Field":1.3200000524520874,"#, + r#""float64Field":1.64,"#, + r#""textField":"hello","#, + r#""dataField":[222,173,190,239,202,254,186,190],"#, + r#""base64Field":"3q2+78r+ur4=","#, + r#""hexField":"deadbeefcafebabe","#, + r#""structField":{"#, + r#""voidField":null,"#, + r#""boolField":false,"#, + r#""int8Field":0,"#, + r#""int16Field":0,"#, + r#""int32Field":0,"#, + r#""int64Field":0,"#, + r#""uInt8Field":0,"#, + r#""uInt16Field":0,"#, + r#""uInt32Field":0,"#, + r#""uInt64Field":0,"#, + r#""float32Field":0,"#, + r#""float64Field":0,"#, + r#""textField":"inner","#, + r#""enumField":"foo","#, + r#""textList":["frist","segund"],"#, + r#""base64List":["3q2+7w==","ut8A0A=="],"#, + r#""hexList":["deadbeef","badf00d0"]"#, + "},", + r#""enumField":"quux","#, + r#""float32List":["NaN","Infinity","-Infinity"],"#, + r#""float64List":["NaN","Infinity","-Infinity"],"#, + r#""enumList":["foo","bar","garply"]"#, + "}" + ); + assert_eq!(expected, json::to_json(root.reborrow_as_reader()).unwrap()); + } + + // Union encoding with flattening + + #[test] + fn test_named_union_non_flattened() { + let mut builder = message::Builder::new_default(); + let mut root: test_union::Builder<'_> = builder.init_root(); + root.set_bit0(true); + root.set_bit2(false); + root.set_bit3(true); + root.set_bit4(false); + root.set_bit5(true); + root.set_bit6(false); + root.set_bit7(true); + root.set_byte0(0xAA); + let mut union0 = root.reborrow().init_union0(); + union0.set_u0f0sp("not this one"); + union0.set_u0f0s16(-12345); + + let expected = concat!( + "{", + r#""union0":{"u0f0s16":-12345},"#, + r#""union1":{"u1f0s0":null},"#, + r#""union2":{"u2f0s1":false},"#, + r#""union3":{"u3f0s1":false},"#, + r#""bit0":true,"#, + r#""bit2":false,"#, + r#""bit3":true,"#, + r#""bit4":false,"#, + r#""bit5":true,"#, + r#""bit6":false,"#, + r#""bit7":true,"#, + r#""byte0":170"#, + "}", + ); + + assert_eq!(expected, json::to_json(root.reborrow_as_reader()).unwrap()); + } + + #[test] + fn test_unnamed_union() { + let mut builder = message::Builder::new_default(); + let mut root: test_unnamed_union::Builder<'_> = builder.init_root(); + root.set_before("before"); + root.set_middle(1234); + root.set_after("after"); + root.set_foo(16); + root.set_bar(32); + let expected = concat!( + "{", + r#""before":"before","#, + r#""middle":1234,"#, + r#""after":"after","#, + r#""bar":32"#, + "}", + ); + assert_eq!(expected, json::to_json(root.reborrow_as_reader()).unwrap()); + } + + #[test] + fn test_named_union_flattened() { + let mut builder = message::Builder::new_default(); + let mut root: test_json_flatten_union::Builder<'_> = builder.init_root(); + root.set_before("before"); + root.set_middle(1234); + root.set_after("after"); + let mut maybe = root.reborrow().init_maybe(); + maybe.set_foo(16); + maybe.set_bar(32); + + let expected = concat!( + "{", + r#""before":"before","#, + r#""maybe_bar":32,"#, + r#""middle":1234,"#, + r#""after":"after","#, + r#""foo":0,"#, + r#""bar":0,"#, + r#""nested_baz":0,"#, + r#""baz":0"#, + "}", + ); + assert_eq!(expected, json::to_json(root.reborrow_as_reader()).unwrap()); + } + + #[test] + fn test_discriminated_union() { + let mut builder = message::Builder::new_default(); + let mut root: test_json_annotations::Builder<'_> = builder.init_root(); + + let mut expected = String::from("{"); + + root.set_some_field("Some Field"); + expected.push_str(r#""names-can_contain!anything Really":"Some Field","#); + + { + let mut a_group = root.reborrow().init_a_group(); + // a_group is flattenned + a_group.set_flat_foo(0xF00); + expected.push_str(r#""flatFoo":3840,"#); + + a_group.set_flat_bar("0xBaa"); + expected.push_str(r#""flatBar":"0xBaa","#); + + a_group.reborrow().init_flat_baz().set_hello(true); + expected.push_str(r#""renamed-flatBaz":{"hello":true},"#); + + a_group.reborrow().init_double_flat().set_flat_qux("Qux"); + expected.push_str(r#""flatQux":"Qux","#); + } + + { + let mut prefixed_group = root.reborrow().init_prefixed_group(); + prefixed_group.set_foo("Foo"); + expected.push_str(r#""pfx.foo":"Foo","#); + + prefixed_group.set_bar(0xBAA); + expected.push_str(r#""pfx.renamed-bar":2986,"#); + + prefixed_group.reborrow().init_baz().set_hello(false); + expected.push_str(r#""pfx.baz":{"hello":false},"#); + + prefixed_group.reborrow().init_more_prefix().set_qux("Qux"); + expected.push_str(r#""pfx.xfp.qux":"Qux","#); + } + + { + let mut a_union_bar = root.reborrow().init_a_union().init_bar(); + expected.push_str(r#""union-type":"renamed-bar","#); + a_union_bar.set_bar_member(0xAAB); + expected.push_str(r#""barMember":2731,"#); + a_union_bar.set_multi_member("Member"); + expected.push_str(r#""multiMember":"Member","#); + } + + { + let mut dependency = root.reborrow().init_dependency(); + dependency.set_foo("dep-foo"); + expected.push_str(r#""dependency":{"renamed-foo":"dep-foo"},"#); + } + + { + let mut simple_group = root.reborrow().init_simple_group(); + simple_group.set_grault("grault"); + expected.push_str(r#""simpleGroup":{"renamed-grault":"grault"},"#); + } + + { + let mut e = root.reborrow().init_enums(4); + e.set(0, crate::json_test_capnp::TestJsonAnnotatedEnum::Foo); + e.set(1, crate::json_test_capnp::TestJsonAnnotatedEnum::Bar); + e.set(2, crate::json_test_capnp::TestJsonAnnotatedEnum::Baz); + e.set(3, crate::json_test_capnp::TestJsonAnnotatedEnum::Qux); + expected.push_str(r#""enums":["foo","renamed-bar","renamed-baz","qux"],"#); + } + + { + let mut b_union = root.reborrow().init_b_union(); + expected.push_str(r#""bUnion":"renamed-bar","#); + b_union.set_bar(100); + expected.push_str(r#""bValue":100,"#); + } + + { + let mut external_union = root.reborrow().init_external_union(); + external_union.reborrow().init_bar().set_value("Value"); + expected.push_str(r#""externalUnion":{"type":"bar","value":"Value"},"#); + } + + { + let mut union_with_void = root.reborrow().init_union_with_void(); + union_with_void.set_void_value(()); + expected.push_str(r#""unionWithVoid":{"type":"voidValue"},"#); + } + + expected.pop(); // Remove trailing comma + expected.push('}'); + + assert_eq!(expected, json::to_json(root.reborrow_as_reader()).unwrap()); + } + + #[test] + fn test_base64_union() { + let mut builder = message::Builder::new_default(); + let mut root: crate::json_test_capnp::test_base64_union::Builder<'_> = builder.init_root(); + + root.set_foo(&[0xde, 0xad, 0xbe, 0xef]); + assert_eq!( + r#"{"foo":"3q2+7w=="}"#, + json::to_json(root.reborrow_as_reader()).unwrap() + ); + } + + #[test] + fn test_string_encoding() { + let mut builder = message::Builder::new_default(); + let mut root: crate::json_test_capnp::test_flattened_struct::Builder<'_> = + builder.init_root(); + + root.set_value(""); + assert_eq!( + r#"{"value":""}"#, + json::to_json(root.reborrow_as_reader()).unwrap() + ); + + root.set_value("tab: \t, newline: \n, carriage return: \r, quote: \", backslash: \\"); + assert_eq!( + r#"{"value":"tab: \t, newline: \n, carriage return: \r, quote: \", backslash: \\"}"#, + json::to_json(root.reborrow_as_reader()).unwrap() + ); + + root.set_value("unicode: †eśt"); + assert_eq!( + r#"{"value":"unicode: †eśt"}"#, + json::to_json(root.reborrow_as_reader()).unwrap() + ); + + root.set_value("backspace: \u{0008}, formfeed: \u{000C}"); + assert_eq!( + r#"{"value":"backspace: \b, formfeed: \f"}"#, + json::to_json(root.reborrow_as_reader()).unwrap() + ); + + root.set_value("bell: \u{0007}, SOH: \u{0001}"); + assert_eq!( + r#"{"value":"bell: \u0007, SOH: \u0001"}"#, + json::to_json(root.reborrow_as_reader()).unwrap() + ); + } + + #[test] + fn test_nested_data_list() -> capnp::Result<()> { + let mut builder = message::Builder::new_default(); + let mut root = builder.init_root::>(); + let mut awd = root.reborrow().init_data_all_the_way_down(2); + let mut first = awd.reborrow().init(0, 2); + first.set(0, &[0xde, 0xad, 0xbe, 0xef]); + first.set(1, &[0xef, 0xbe, 0xad, 0xde]); + let mut second = awd.reborrow().init(1, 1); + second.set(0, &[0xba, 0xdf, 0x00, 0xd0]); + + assert_eq!( + r#"{"dataAllTheWayDown":[["deadbeef","efbeadde"],["badf00d0"]]}"#, + json::to_json(root.reborrow_as_reader())? + ); + + Ok(()) + } + + // Decode + + #[test] + fn test_decode_simple() -> capnp::Result<()> { + let mut builder = message::Builder::new_default(); + let mut root: test_json_types::Builder<'_> = builder.init_root(); + json::from_json( + r#" + { + "voidField": null, + "boolField": true, + "int8Field": -8, + "int16Field": -16, + "int32Field": -32, + "int64Field": -64, + "uInt8Field": 8, + "uInt16Field": 16, + "uInt32Field": 32, + "uInt64Field": 64, + "float32Field": 1.3200000524520874, + "float64Field": 0.164e2, + "textField": "hello", + "dataField": [ + 222, + 173 + + , + + 190, + 239, + 202, + 254, + 186, + 190 + ], + "base64Field": "3q2+78r+ur4=", + "hexField": "deadbeefcafebabe", + "structField": { + "voidField": null, + "boolField": false, + "int8Field": 0, + "int16Field": 0, + "int32Field": 0, + "int64Field": 0, + "uInt8Field": 0, + "uInt16Field" + : 0, + "uInt32Field": 0, + "uInt64Field": 0, + "float32Field": 0, + "float64Field": 0, + "textField": "inner", + "enumField": "foo", + "textList": [ + "frist", + "segund" + ], + "base64List": [ + "3q2+7w==", + "ut8A0A==" + ], + "hexList": [ + "deadbeef", + "badf00d0" + ] + }, + "enumField": "quux", + "float32List": [ + "NaN", + "Infinity", + "-Infinity" + ], + "float64List": [ + "NaN", + "Infinity" , + "-Infinity" + ], + "enumList": [ + "foo", + "bar", + "garply" + ], + "int64List": [ + 1, + 2, + 4, + 8 + ] + } + "#, + root.reborrow(), + )?; + + let reader = root.into_reader(); + assert_eq!((), reader.get_void_field()); + assert!(reader.get_bool_field()); + assert_eq!(-8, reader.get_int8_field()); + assert_eq!(-16, reader.get_int16_field()); + assert_eq!(-32, reader.get_int32_field()); + assert_eq!(-64, reader.get_int64_field()); + assert_eq!(8, reader.get_u_int8_field()); + assert_eq!(16, reader.get_u_int16_field()); + assert_eq!(32, reader.get_u_int32_field()); + assert_eq!(64, reader.get_u_int64_field()); + assert_eq!(1.32, reader.get_float32_field()); + assert_eq!(16.4, reader.get_float64_field()); + assert_eq!("hello", reader.get_text_field()?.to_str()?); + assert_eq!( + [0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe], + reader.get_data_field()? + ); + assert_eq!( + [0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe], + reader.get_base64_field()? + ); + assert_eq!( + [0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe], + reader.get_hex_field()? + ); + + for i in 0..4 { + assert_eq!(1 << i, reader.get_int64_list()?.get(i as u32)); + } + + Ok(()) + } + + #[test] + fn test_encode_with_empty_flattened() -> capnp::Result<()> { + let mut builder = capnp::message::Builder::new_default(); + let root = + builder.init_root::>(); + + assert_eq!( + r#"{"flatFoo":0,"renamed-flatBaz":{"hello":false},"pfx.renamed-bar":0,"pfx.baz":{"hello":false},"union-type":"foo","multiMember":0,"simpleGroup":{},"unionWithVoid":{"type":"intValue","intValue":0}}"#, + json::to_json(root.reborrow_as_reader())? + ); + + Ok(()) + } + + #[test] + fn test_decode_flattened() -> capnp::Result<()> { + let j = r#" + { + "names-can_contain!anything Really": "Some Field", + "flatFoo": 1234, + "flatBar": "0xBaa", + "renamed-flatBaz": {"hello": true}, + "flatQux": "Qux", + "pfx.baz": {"hello": true}, + "union-type": "renamed-bar", + "barMember": 2731, + "multiMember": "Member", + "bUnion": "renamed-bar", + "bValue": 100 + } + "#; + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(j, root.reborrow())?; + + let reader = root.into_reader(); + assert_eq!("Some Field", reader.get_some_field()?.to_str()?); + assert_eq!(1234, reader.get_a_group().get_flat_foo()); + assert_eq!("0xBaa", reader.get_a_group().get_flat_bar()?.to_str()?); + assert!(reader.get_a_group().get_flat_baz().get_hello()); + assert_eq!( + "Qux", + reader + .get_a_group() + .get_double_flat() + .get_flat_qux()? + .to_str()? + ); + assert!(reader.get_prefixed_group().get_baz().get_hello()); + assert!(matches!( + reader.get_a_union().which()?, + crate::json_test_capnp::test_json_annotations::a_union::Bar(_) + )); + { + let bar = match reader.get_a_union().which()? { + crate::json_test_capnp::test_json_annotations::a_union::Bar(b) => b, + _ => panic!("Expected Bar"), + }; + assert_eq!(2731, bar.get_bar_member()); + assert_eq!("Member", bar.get_multi_member()?.to_str()?); + } + assert!(matches!( + reader.get_b_union().which()?, + crate::json_test_capnp::test_json_annotations::b_union::Bar(_) + )); + { + let bar = match reader.get_b_union().which()? { + crate::json_test_capnp::test_json_annotations::b_union::Bar(b) => b, + _ => panic!("Expected Bar"), + }; + assert_eq!(100, bar); + } + + Ok(()) + } + + #[test] + fn test_decode_base64_union() -> capnp::Result<()> { + { + let j = r#" + { + "foo":"3q2+7w==" + } + "#; + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(j, root.reborrow())?; + + let reader = root.into_reader(); + assert!(matches!( + reader.which()?, + crate::json_test_capnp::test_base64_union::Foo(_) + )); + { + let foo = match reader.which()? { + crate::json_test_capnp::test_base64_union::Foo(f) => f, + _ => panic!("Expected Foo"), + }?; + assert_eq!(&[0xde, 0xad, 0xbe, 0xef], foo); + } + } + + { + let j = r#" + { + "bar":"To the bar!" + } + "#; + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(j, root.reborrow())?; + + let reader = root.into_reader(); + assert!(matches!( + reader.which()?, + crate::json_test_capnp::test_base64_union::Bar(_) + )); + { + let bar = match reader.which()? { + crate::json_test_capnp::test_base64_union::Bar(b) => b?, + _ => panic!("Expected Foo"), + }; + assert_eq!("To the bar!", bar.to_str()?); + } + } + + // When both variants are present, we pick the first one in the spec + { + let j = r#" + { + "bar":"To the bar!", + "foo":"3q2+7w==" + } + "#; + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(j, root.reborrow())?; + + let reader = root.into_reader(); + assert!(matches!( + reader.which()?, + crate::json_test_capnp::test_base64_union::Foo(_) + )); + { + let foo = match reader.which()? { + crate::json_test_capnp::test_base64_union::Foo(f) => f, + _ => panic!("Expected Foo"), + }?; + assert_eq!(&[0xde, 0xad, 0xbe, 0xef], foo); + } + } + + { + let j = r#" + { + "bar":"To the bar!", + "foo":"3q2+7w==" + } + "#; + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(j, root.reborrow())?; + + let reader = root.into_reader(); + assert!(matches!( + reader.which()?, + crate::json_test_capnp::test_renamed_anon_union::Bar(_) + )); + { + let bar = match reader.which()? { + crate::json_test_capnp::test_renamed_anon_union::Bar(b) => b?, + _ => panic!("Expected Foo"), + }; + assert_eq!("To the bar!", bar.to_str()?); + } + } + + { + let j = r#" + { + "bar":"To the bar!", + "renamed-foo":"3q2+7w==" + } + "#; + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(j, root.reborrow())?; + + let reader = root.into_reader(); + assert!(matches!( + reader.which()?, + crate::json_test_capnp::test_renamed_anon_union::Foo(_) + )); + { + let foo = match reader.which()? { + crate::json_test_capnp::test_renamed_anon_union::Foo(f) => f, + _ => panic!("Expected Foo"), + }?; + assert_eq!(&[0xde, 0xad, 0xbe, 0xef], foo); + } + } + Ok(()) + } + + #[test] + fn test_decode_nested_data_list() -> capnp::Result<()> { + let json = r#"{"dataAllTheWayDown":[["deadbeef","efbeadde"],["badf00d0"]]}"#; + let mut builder = message::Builder::new_default(); + let mut root = builder.init_root::>(); + json::from_json(json, root.reborrow())?; + + let reader = root.into_reader(); + + { + let awd = reader.get_data_all_the_way_down()?; + let first = awd.get(0)?; + assert_eq!(2, first.len()); + assert_eq!(&[0xde, 0xad, 0xbe, 0xef], first.get(0)?); + assert_eq!(&[0xef, 0xbe, 0xad, 0xde], first.get(1)?); + let second = awd.get(1)?; + assert_eq!(1, second.len()); + assert_eq!(&[0xba, 0xdf, 0x00, 0xd0], second.get(0)?); + } + + Ok(()) + } + + #[test] + fn test_decode_union_with_void() -> capnp::Result<()> { + let json = r#" + { + "unionWithVoid": { + "type": "voidValue" + } + } + "#; + + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(json, root.reborrow())?; + + let reader = root.into_reader(); + assert!(matches!( + reader.get_union_with_void().which()?, + crate::json_test_capnp::test_json_annotations::union_with_void::VoidValue(_) + )); + + Ok(()) + } + + #[test] + fn test_encode_decode_no_name_discriminator() -> capnp::Result<()> { + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + root.reborrow().init_baz().set_bar(100); + root.reborrow().init_sbaz().set_sfoo("Hello"); + let json = json::to_json(root.reborrow_as_reader())?; + assert_eq!(r#"{"baz":{"bar":100},"sbaz":"sfoo","sfoo":"Hello"}"#, json); + + let mut builder = capnp::message::Builder::new_default(); + let mut root = + builder.init_root::>(); + json::from_json(&json, root.reborrow())?; + let reader = root.into_reader(); + assert_eq!( + 100, + match reader.get_baz().which()? { + crate::json_test_capnp::unnamed_discriminator::baz::Bar(b) => b, + _ => panic!("Expected Bar"), + }, + ); + assert_eq!( + "Hello", + match reader.get_sbaz().which()? { + crate::json_test_capnp::unnamed_discriminator::sbaz::Sfoo(s) => s?.to_str()?, + _ => panic!("Expected Sfoo"), + } + ); + + Ok(()) + } +} diff --git a/capnp-json/test/test.capnp b/capnp-json/test/test.capnp new file mode 100644 index 000000000..5e74480e9 --- /dev/null +++ b/capnp-json/test/test.capnp @@ -0,0 +1,863 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +@0x99d187209d25cee7; + +using Json = import "/capnp/compat/json.capnp"; + +struct FieldSubsetIndexesCorrectly { + common @2 :Text; + + union { + unset @0 :Void; + variant @1 :UInt8; + } +} + +struct TestPrimList { + uint8List @0 : List(UInt8); + int8List @1 : List(Int8); + uint16List @2 : List(UInt16); + int16List @3 : List(Int16); + uint32List @4 : List(UInt32); + int32List @5 : List(Int32); + uint64List @6 : List(UInt64); + int64List @7 : List(Int64); + float32List @8 : List(Float32); + boolList @9 : List(Bool); + voidList @10 : List(Void); +} + +struct TestStructList { + structList @0 : List(TestPrimList); +} + +struct TestBlob { + textField @0 : Text; + dataField @1 : Data; +} + +struct TestBigStruct { + voidField @0 : Void; + boolField @1 : Bool; + int8Field @2 : Int8; + int16Field @3 : Int16; + int32Field @4 : Int32; + int64Field @5 : Int64; + uint8Field @6 : UInt8; + uint16Field @7 : UInt16; + uint32Field @8 : UInt32; + uint64Field @9 : UInt64; + float32Field @10 : Float32; + float64Field @11 : Float64; + + structField @12 : Inner; + anotherStructField @13 : Inner; + + struct Inner { + uint32Field @0 : UInt32; + uint64Field @1 : UInt64; + float32Field @2 : Float32; + float64Field @3 : Float64; + boolFieldA @4 : Bool; + boolFieldB @5 : Bool; + boolFieldC @6 : Bool; + boolFieldD @7 : Bool; + } +} + +enum AnEnum { + foo @0; + bar @1; + baz @2; + qux @3; +} + +struct TestComplexList { + enumList @0 : List(AnEnum); + textList @1 : List(Text); + dataList @2 : List(Data); + primListList @3 : List(List(Int32)); + primListListList @4 : List(List(List(Int16))); + enumListList @5 : List(List(AnEnum)); + textListList @6 : List(List(Text)); + dataListList @7 : List(List(Data)); + structListList @8 : List(List(TestBigStruct)); +} + +enum TestEnum { + foo @0; + bar @1; + baz @2; + qux @3; + quux @4; + corge @5; + grault @6; + garply @7; +} + +enum TestEnumWithTrickyNames { + foo @0; + bar @1; + error @2; +} + +struct TestAllTypes { + voidField @0 : Void; + boolField @1 : Bool; + int8Field @2 : Int8; + int16Field @3 : Int16; + int32Field @4 : Int32; + int64Field @5 : Int64; + uInt8Field @6 : UInt8; + uInt16Field @7 : UInt16; + uInt32Field @8 : UInt32; + uInt64Field @9 : UInt64; + float32Field @10 : Float32; + float64Field @11 : Float64; + textField @12 : Text; + dataField @13 : Data; + structField @14 : TestAllTypes; + enumField @15 : TestEnum; + interfaceField @16 : EmptyInterface; + + voidList @17 : List(Void); + boolList @18 : List(Bool); + int8List @19 : List(Int8); + int16List @20 : List(Int16); + int32List @21 : List(Int32); + int64List @22 : List(Int64); + uInt8List @23 : List(UInt8); + uInt16List @24 : List(UInt16); + uInt32List @25 : List(UInt32); + uInt64List @26 : List(UInt64); + float32List @27 : List(Float32); + float64List @28 : List(Float64); + textList @29 : List(Text); + dataList @30 : List(Data); + structList @31 : List(TestAllTypes); + enumList @32 : List(TestEnum); + interfaceList @33 : List(EmptyInterface); +} + +struct TestDefaults { + voidField @0 :Void = void; + boolField @1 :Bool = true; + int8Field @2 :Int8 = -123; + int16Field @3 :Int16 = -12345; + int32Field @4 :Int32 = -12345678; + int64Field @5 :Int64 = -123456789012345; + uInt8Field @6 :UInt8 = 234; + uInt16Field @7 :UInt16 = 45678; + uInt32Field @8 :UInt32 = 3456789012; + uInt64Field @9 :UInt64 = 12345678901234567890; + float32Field @10 :Float32 = 1234.5; + float64Field @11 :Float64 = -123e45; + textField @12 :Text = "foo"; + dataField @13 :Data = 0x"62 61 72"; # "bar" + structField @14 : TestAllTypes = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + textField = "nested", + structField = (textField = "really nested")), + enumField = baz, + # interfaceField can't have a default + + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -0x80, 0x7f], + int16List = [1234, -5678, -0x8000, 0x7fff], + int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], + int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], + uInt8List = [12, 34, 0, 0xff], + uInt16List = [1234, 5678, 0, 0xffff], + uInt32List = [12345678, 90123456, 0, 0xffffffff], + uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + (textField = "x structlist 1"), + (textField = "x structlist 2"), + (textField = "x structlist 3")], + enumList = [qux, bar, grault] + # interfaceList can't have a default + ); + + enumField @15 : TestEnum = corge; + interfaceField @16 : Void; # TODO + + voidList @17 : List(Void) = [void, void, void, void, void, void]; + boolList @18 : List(Bool) = [true, false, false, true]; + int8List @19 : List(Int8) = [111, -111]; + int16List @20 : List(Int16) = [11111, -11111]; + int32List @21 : List(Int32) = [111111111, -111111111]; + int64List @22 : List(Int64) = [1111111111111111111, -1111111111111111111]; + uInt8List @23 : List(UInt8) = [111, 222] ; + uInt16List @24 : List(UInt16) = [33333, 44444]; + uInt32List @25 : List(UInt32) = [3333333333]; + uInt64List @26 : List(UInt64) = [11111111111111111111]; + float32List @27 : List(Float32) = [5555.5, inf, -inf, nan]; + float64List @28 : List(Float64) = [7777.75, inf, -inf, nan]; + textList @29 : List(Text) = ["plugh", "xyzzy", "thud"]; + dataList @30 : List(Data) = ["oops", "exhausted", "rfc3092"]; + structList @31 : List(TestAllTypes) = [ + (textField = "structlist 1"), + (textField = "structlist 2"), + (textField = "structlist 3")]; + enumList @32 : List(TestEnum) = [foo, garply]; + interfaceList @33 : List(Void); # TODO +} + +struct TestAnyPointer { + anyPointerField @0 :AnyPointer; +} + +struct TestUnion { + union0 @0! :union { + # Pack union 0 under ideal conditions: there is no unused padding space prior to it. + u0f0s0 @4: Void; + u0f0s1 @5: Bool; + u0f0s8 @6: Int8; + u0f0s16 @7: Int16; + u0f0s32 @8: Int32; + u0f0s64 @9: Int64; + u0f0sp @10: Text; + + # Pack more stuff into union0 -- should go in same space. + u0f1s0 @11: Void; + u0f1s1 @12: Bool; + u0f1s8 @13: Int8; + u0f1s16 @14: Int16; + u0f1s32 @15: Int32; + u0f1s64 @16: Int64; + u0f1sp @17: Text; + } + + # Pack one bit in order to make pathological situation for union1. + bit0 @18: Bool; + + union1 @1! :union { + # Pack pathologically bad case. Each field takes up new space. + u1f0s0 @19: Void; + u1f0s1 @20: Bool; + u1f1s1 @21: Bool; + u1f0s8 @22: Int8; + u1f1s8 @23: Int8; + u1f0s16 @24: Int16; + u1f1s16 @25: Int16; + u1f0s32 @26: Int32; + u1f1s32 @27: Int32; + u1f0s64 @28: Int64; + u1f1s64 @29: Int64; + u1f0sp @30: Text; + u1f1sp @31: Text; + + # Pack more stuff into union1 -- each should go into the same space as corresponding u1f0s*. + u1f2s0 @32: Void; + u1f2s1 @33: Bool; + u1f2s8 @34: Int8; + u1f2s16 @35: Int16; + u1f2s32 @36: Int32; + u1f2s64 @37: Int64; + u1f2sp @38: Text; + } + + # Fill in the rest of that bitfield from earlier. + bit2 @39: Bool; + bit3 @40: Bool; + bit4 @41: Bool; + bit5 @42: Bool; + bit6 @43: Bool; + bit7 @44: Bool; + + # Interleave two unions to be really annoying. + # Also declare in reverse order to make sure union discriminant values are sorted by field number + # and not by declaration order. + union2 @2! :union { + u2f0s64 @54: Int64; + u2f0s32 @52: Int32; + u2f0s16 @50: Int16; + u2f0s8 @47: Int8; + u2f0s1 @45: Bool; + } + + union3 @3! :union { + u3f0s64 @55: Int64; + u3f0s32 @53: Int32; + u3f0s16 @51: Int16; + u3f0s8 @48: Int8; + u3f0s1 @46: Bool; + } + + byte0 @49: UInt8; +} + +struct TestUnnamedUnion { + before @0 :Text; + + union { + foo @1 :UInt16; + bar @3 :UInt32; + } + + middle @2 :UInt16; + + after @4 :Text; +} + +struct TestGroups { + groups :union { + foo :group { + corge @0 :Int32; + grault @2 :Int64; + garply @8 :Text; + } + bar :group { + corge @3 :Int32; + grault @4 :Text; + garply @5 :Int64; + } + baz :group { + corge @1 :Int32; + grault @6 :Text; + garply @7 :Text; + quz @9 :Float64; + anEnum @10 :TestEnum; + } + } +} + +struct TestUnionDefaults { + s16s8s64s8Set @0 :TestUnion = + (union0 = (u0f0s16 = 321), union1 = (u1f0s8 = 123), union2 = (u2f0s64 = 12345678901234567), + union3 = (u3f0s8 = 55)); + s0sps1s32Set @1 :TestUnion = + (union0 = (u0f1s0 = void), union1 = (u1f0sp = "foo"), union2 = (u2f0s1 = true), + union3 = (u3f0s32 = 12345678)); + + unnamed1 @2 :TestUnnamedUnion = (foo = 123); + unnamed2 @3 :TestUnnamedUnion = (bar = 321, before = "foo", after = "bar"); + + inner1 :union { + a @4 :UInt8 = 17; + b @5 :Text = "foobar"; + } + + inner2 :union { + c @6 :Text = "grault"; + d @7 :UInt8 = 19; + } +} + +struct TestLists { + struct Struct0 { f @0 :Void; } + struct Struct1 { f @0 :Bool; } + struct Struct8 { f @0 :UInt8; } + struct Struct16 { f @0 :UInt16; } + struct Struct32 { f @0 :UInt32; } + struct Struct64 { f @0 :UInt64; } + struct StructP { f @0 :Text; } + + struct Struct0c { f @0 :Void; pad @1 :Text; } + struct Struct1c { f @0 :Bool; pad @1 :Text; } + struct Struct8c { f @0 :UInt8; pad @1 :Text; } + struct Struct16c { f @0 :UInt16; pad @1 :Text; } + struct Struct32c { f @0 :UInt32; pad @1 :Text; } + struct Struct64c { f @0 :UInt64; pad @1 :Text; } + struct StructPc { f @0 :Text; pad @1 :UInt64; } + + list0 @0 :List(Struct0); + list1 @1 :List(Struct1); + list8 @2 :List(Struct8); + list16 @3 :List(Struct16); + list32 @4 :List(Struct32); + list64 @5 :List(Struct64); + listP @6 :List(StructP); + + int32ListList @7 :List(List(Int32)); + textListList @8 :List(List(Text)); + structListList @9 :List(List(TestAllTypes)); +} + +struct TestOldVersion { + # A subset of TestNewVersion. + old1 @0 :Int64; + old2 @1 :Text; + old3 @2 :TestOldVersion; + old4 @3 :List(Text); +} + +struct TestNewVersion { + # A superset of TestOldVersion. + old1 @0 :Int64; + old2 @1 :Text; + old3 @2 :TestNewVersion; + + struct UpgradedFromText { + textField @0 :Text; + int32Field @1 :Int32; + dataField @2 :Data; + } + old4 @3 :List(UpgradedFromText); + new1 @4 :Int64 = 987; + new2 @5 :Text = "baz"; + new3 @6 :TestDefaults; +} + +struct TestOldUnionVersion { + union { + a @0 :Void; + b @1 :UInt64; + } +} + +struct TestNewUnionVersion { + union { + a :union { + a0 @0 :Void; + a1 @2 :UInt64; + } + b @1 :UInt64; + } +} + +struct TestGenerics(Foo, Bar) { + foo @0 :Foo; + bar @1 :Bar; + rev @2 :TestGenerics(Bar, Foo); + dub @3 :TestGenerics(Text, List(UInt8)); + + struct Inner { + foo @0 :Foo; + bar @1 :Bar; + } + + struct Inner2(Baz) { + bar @0 :Bar; + baz @1 :Baz; + innerBound @2 :Inner; + innerUnbound @3 :TestGenerics.Inner; + + struct DeepNest(Qux) { + foo @0 :Foo; + bar @1 :Bar; + baz @2 :Baz; + qux @3 :Qux; + } + } + + interface Interface(Qux) { + call @0 Inner2(Text) -> (qux :Qux, gen :TestGenerics(TestAllTypes, TestAnyPointer)); + otherCall @1 Inner2(List(Text)) -> Inner2(List(Int16)); + } + + annotation ann(struct) :Foo; + + using AliasFoo = Foo; + using AliasInner = Inner; + using AliasInner2 = Inner2; + using AliasInner2Text = Inner2(Text); + using AliasRev = TestGenerics(Bar, Foo); + + struct UseAliases { + foo @0 :AliasFoo; + inner @1 :AliasInner; + inner2 @2 :AliasInner2; + inner2Bind @3 :AliasInner2(Text); + inner2Text @4 :AliasInner2Text; + revFoo @5 :AliasRev.AliasFoo; + } +} + +struct TestGenericsWrapper(Foo, Bar) { + value @0 :TestGenerics(Foo, Bar); +} + +struct TestGenericsWrapper2 { + value @0 :TestGenericsWrapper(Text, TestAllTypes); +} + +interface TestImplicitMethodParams { + call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); +} + +interface TestImplicitMethodParamsInGeneric(V) { + call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); + call1 @1 [T, U] TestGenerics(T, U) -> (foo :T, bar: U); + call2 @2 [T, U] TestGenerics(T, U) -> TestAllTypes; + call3 @3 [T, U] TestAllTypes -> TestAllTypes; + call4 @4 [T, U] TestGenerics(V, V) -> TestGenerics(V, AnyPointer); +} + +struct TestGenericsUnion(Foo, Bar) { + union { + foo1 @0 :Foo; + bar1 @1 :Bar; + foo2 @2 :Foo; + } +} + +struct TestGenericsGroups(T1, T2) { + foo @0 :T1; + bar :group { + baz @1 :T2; + } + + struct Inner(T3, T4) { + foo @0 :T3; + bar :union { + baz @1 :Void; + qux @2 :Int32; + } + } +} + +struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") { + basic @0 :TestGenerics(TestAllTypes, TestAnyPointer); + inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner; + inner2 @2 :TestGenerics(TestAllTypes, TestAnyPointer).Inner2(Text); + unspecified @3 :TestGenerics; + unspecifiedInner @4 :TestGenerics.Inner2(Text); + wrapper @8 :TestGenericsWrapper(TestAllTypes, TestAnyPointer); + cap @18 :TestGenerics(TestInterface, Text); + + genericCap @19 :TestGenerics(TestAllTypes, List(UInt32)).Interface(Data); + + default @5 :TestGenerics(TestAllTypes, Text) = + (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); + defaultInner @6 :TestGenerics(TestAllTypes, Text).Inner = + (foo = (int16Field = 123), bar = "text"); + defaultUser @7 :TestUseGenerics = (basic = (foo = (int16Field = 123))); + defaultWrapper @9 :TestGenericsWrapper(Text, TestAllTypes) = + (value = (foo = "text", rev = (foo = (int16Field = 321)))); + defaultWrapper2 @10 :TestGenericsWrapper2 = + (value = (value = (foo = "text", rev = (foo = (int16Field = 321))))); + + aliasFoo @11 :TestGenerics(TestAllTypes, TestAnyPointer).AliasFoo = (int16Field = 123); + aliasInner @12 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner + = (foo = (int16Field = 123)); + aliasInner2 @13 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2 + = (innerBound = (foo = (int16Field = 123))); + aliasInner2Bind @14 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2(List(UInt32)) + = (baz = [12, 34], innerBound = (foo = (int16Field = 123))); + aliasInner2Text @15 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2Text + = (baz = "text", innerBound = (foo = (int16Field = 123))); + aliasRev @16 :TestGenerics(TestAnyPointer, Text).AliasRev.AliasFoo = "text"; + + useAliases @17 :TestGenerics(TestAllTypes, List(UInt32)).UseAliases = ( + foo = (int16Field = 123), + inner = (foo = (int16Field = 123)), + inner2 = (innerBound = (foo = (int16Field = 123))), + inner2Bind = (baz = "text", innerBound = (foo = (int16Field = 123))), + inner2Text = (baz = "text", innerBound = (foo = (int16Field = 123)))); +} + +struct TestEmptyStruct {} + +struct TestConstants { + const voidConst :Void = void; + const boolConst :Bool = true; + const int8Const :Int8 = -123; + const int16Const :Int16 = -12345; + const int32Const :Int32 = -12345678; + const int64Const :Int64 = -123456789012345; + const uint8Const :UInt8 = 234; + const uint16Const :UInt16 = 45678; + const uint32Const :UInt32 = 3456789012; + const uint64Const :UInt64 = 12345678901234567890; + const float32Const :Float32 = 1234.5; + const float64Const :Float64 = -123e45; + const textConst :Text = "foo"; + const complexTextConst :Text = "foo\"☺\'$$$"; + const dataConst :Data = "bar"; + const structConst :TestAllTypes = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + textField = "nested", + structField = (textField = "really nested")), + enumField = baz, + + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -0x80, 0x7f], + int16List = [1234, -5678, -0x8000, 0x7fff], + int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], + int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], + uInt8List = [12, 34, 0, 0xff], + uInt16List = [1234, 5678, 0, 0xffff], + uInt32List = [12345678, 90123456, 0, 0xffffffff], + uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + (textField = "x structlist 1"), + (textField = "x structlist 2"), + (textField = "x structlist 3")], + enumList = [qux, bar, grault] + ); + + const enumConst :TestEnum = corge; + + const voidListConst :List(Void) = [void, void, void, void, void, void]; + const boolListConst :List(Bool) = [true, false, false, true]; + const int8ListConst :List(Int8) = [111, -111]; + const int16ListConst :List(Int16) = [11111, -11111]; + const int32ListConst :List(Int32) = [111111111, -111111111]; + const int64ListConst :List(Int64) = [1111111111111111111, -1111111111111111111]; + const uint8ListConst :List(UInt8) = [111, 222] ; + const uint16ListConst :List(UInt16) = [33333, 44444]; + const uint32ListConst :List(UInt32) = [3333333333]; + const uint64ListConst :List(UInt64) = [11111111111111111111]; + const float32ListConst :List(Float32) = [5555.5, inf, -inf, nan]; + const float64ListConst :List(Float64) = [7777.75, inf, -inf, nan]; + const textListConst :List(Text) = ["plugh", "xyzzy", "thud"]; + const dataListConst :List(Data) = ["oops", "exhausted", "rfc3092"]; + const structListConst :List(TestAllTypes) = [ + (textField = "structlist 1"), + (textField = "structlist 2"), + (textField = "structlist 3")]; + const enumListConst :List(TestEnum) = [foo, garply]; +} + +const globalInt :UInt32 = 12345; + +struct TestFloatConsts { + const a :Float32 = inf; + const b :Float32 = -inf; + const c :Float32 = nan; + + const x :Float64 = inf; + const y :Float64 = -inf; + const z :Float64 = nan; + + const pi32 : Float32 = 3.14159265358979323846264338327950288; + const pi64 : Float64 = 3.14159265358979323846264338327950288; +} + +interface TestInterface { + foo @0 (i :UInt32, j :Bool) -> (x : Text); + bar @1 () -> (); + baz @2 (s : TestBigStruct); + bazz @3 (s : TestBigStruct) -> (r : TestBigStruct); +} + +interface TestExtends extends(TestInterface) { + qux @0 (); + corge @1 TestBigStruct -> (); + grault @2 () -> TestBigStruct; +} + +struct TestCapabilityList { + foo @0 :List(TestInterface); +} + +interface EmptyInterface {} + +struct TestKeywords { + struct As {} + struct Box {} + struct Break {} + struct Continue {} + struct Crate {} + struct Else {} + struct Enum {} + struct Extern {} + # ... + struct Struct{} + struct Super{} + struct True{} + struct Trait{} + struct Type{} + struct Unsafe{} + struct Use{} + struct While{} +} + +struct Issue77 { + data :union { + a @0 :UInt16; + b @1 :UInt8; + } + + text :union { + c @2 :Bool; + d @3 :Int32; + } + + layout :union { + e @4 :Void; + f @5 :Void; + } + + structList :union { + g @6 :Void; + h @7 :Void; + } + + enumList :union { + i @8 :Void; + j @9 :Void; + } + + primitiveList :union { + k @10 :Void; + l @11 :Void; + } + + dataList :union { + m @12 :Void; + n @13 :Void; + } + + textList :union { + o @14 :Void; + p @15 :Void; + } + + listList :union { + q @16 :Void; + r @17 :Void; + } +} + +struct GenericOnce(Foo) { + genericField @0 : Foo; +} + +struct BrandOnce { + brandedField @0 : GenericOnce(TestAllTypes); +} + +struct GenericTwice(Foo,Bar) { + fooField @0 : Foo; + barField @1 : Bar; +} + +struct BrandTwice { + bazField @0 : GenericTwice(Text, TestBlob); +} + +struct Map(Key, Value) { + entries @0 :List(Entry); + struct Entry { + key @0 :Key; + value @1 :Value; + } +} + +interface GenericBase(T) {} +interface GenericExtend extends(GenericBase(Data)) {} +interface GenericExtend2 extends (GenericBase(GenericBase(Data))) {} + +struct TestJsonTypes { + voidField @0 : Void; + boolField @1 : Bool; + int8Field @2 : Int8; + int16Field @3 : Int16; + int32Field @4 : Int32; + int64Field @5 : Int64; + uInt8Field @6 : UInt8; + uInt16Field @7 : UInt16; + uInt32Field @8 : UInt32; + uInt64Field @9 : UInt64; + float32Field @10 : Float32; + float64Field @11 : Float64; + textField @12 : Text; + dataField @13 : Data; + base64Field @14 : Data $Json.base64; + hexField @15 : Data $Json.hex; + structField @16 : TestJsonTypes; + enumField @17 : TestEnum; + + voidList @18 : List(Void); + boolList @19 : List(Bool); + int8List @20 : List(Int8); + int16List @21 : List(Int16); + int32List @22 : List(Int32); + int64List @23 : List(Int64); + uInt8List @24 : List(UInt8); + uInt16List @25 : List(UInt16); + uInt32List @26 : List(UInt32); + uInt64List @27 : List(UInt64); + float32List @28 : List(Float32); + float64List @29 : List(Float64); + textList @30 : List(Text); + dataList @31 : List(Data); + base64List @32 : List(Data) $Json.base64; + hexList @33 : List(Data) $Json.hex; + structList @34 : List(TestJsonTypes); + enumList @35 : List(TestEnum); +} + +struct TestJsonFlattenUnion { + before @0 :Text; + + maybe :union $Json.flatten("maybe_") { # field, group, union to test + foo @1 :UInt16; + bar @3 :UInt32; + } + + groupie :group $Json.flatten() { + foo @5 :UInt16; + bar @6 :UInt32; + prefixed :group $Json.flatten("nested_") { + baz @7 :UInt8; + } + nested :group $Json.flatten() { + baz @8 :UInt8; + } + } + + middle @2 :UInt16; + + after @4 :Text; +} diff --git a/capnpc/Cargo.toml b/capnpc/Cargo.toml index 07b0e3deb..0ca61ecd0 100644 --- a/capnpc/Cargo.toml +++ b/capnpc/Cargo.toml @@ -23,7 +23,6 @@ path = "src/capnpc-rust.rs" name = "capnpc-rust-bootstrap" path = "src/capnpc-rust-bootstrap.rs" - [dependencies.capnp] version = "0.23.0" path = "../capnp" diff --git a/capnpc/test-edition-2015/Cargo.toml b/capnpc/test-edition-2015/Cargo.toml index 5953f8e06..ab3946511 100644 --- a/capnpc/test-edition-2015/Cargo.toml +++ b/capnpc/test-edition-2015/Cargo.toml @@ -16,4 +16,4 @@ capnpc = { path = "../" } [dependencies] capnp = { path = "../../capnp" } capnpc = { path = "../" } -external-crate = { path = "../test/external-crate" } \ No newline at end of file +external-crate = { path = "../test/external-crate" } diff --git a/capnpc/test-edition-2018/Cargo.toml b/capnpc/test-edition-2018/Cargo.toml index cff029364..eefe87fcf 100644 --- a/capnpc/test-edition-2018/Cargo.toml +++ b/capnpc/test-edition-2018/Cargo.toml @@ -16,4 +16,4 @@ capnpc = { path = "../" } [dependencies] capnp = { path = "../../capnp" } capnpc = { path = "../" } -external-crate = { path = "../test/external-crate" } \ No newline at end of file +external-crate = { path = "../test/external-crate" }