use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicPtr, Ordering};
use hashbrown::HashMap;
use crate::unknown_fields::{UnknownField, UnknownFields};
pub struct JsonExtEntry {
pub number: u32,
pub full_name: &'static str,
pub extendee: &'static str,
pub to_json: fn(u32, &UnknownFields) -> Result<serde_json::Value, String>,
pub from_json: fn(serde_json::Value, u32) -> Result<Vec<UnknownField>, String>,
}
#[deprecated(since = "0.3.0", note = "renamed to JsonExtEntry")]
pub type ExtensionRegistryEntry = JsonExtEntry;
pub struct ExtensionRegistry {
by_number: HashMap<(String, u32), JsonExtEntry>,
by_name: HashMap<String, (String, u32)>,
}
impl ExtensionRegistry {
pub fn new() -> Self {
Self {
by_number: HashMap::new(),
by_name: HashMap::new(),
}
}
pub fn register(&mut self, entry: JsonExtEntry) {
let key = (entry.extendee.to_owned(), entry.number);
self.by_name.insert(entry.full_name.to_owned(), key.clone());
self.by_number.insert(key, entry);
}
pub fn by_number(&self, extendee: &str, number: u32) -> Option<&JsonExtEntry> {
self.by_number.get(&(extendee.to_owned(), number))
}
pub fn by_name(&self, full_name: &str) -> Option<&JsonExtEntry> {
let key = self.by_name.get(full_name)?;
self.by_number.get(key)
}
}
impl Default for ExtensionRegistry {
fn default() -> Self {
Self::new()
}
}
static REGISTRY: AtomicPtr<ExtensionRegistry> = AtomicPtr::new(core::ptr::null_mut());
#[deprecated(since = "0.3.0", note = "use buffa::type_registry::set_type_registry")]
pub fn set_extension_registry(reg: Box<ExtensionRegistry>) {
let old = REGISTRY.swap(Box::into_raw(reg), Ordering::Release);
if !old.is_null() {
let _ = old;
}
}
pub fn extension_registry() -> Option<&'static ExtensionRegistry> {
let ptr = REGISTRY.load(Ordering::Acquire);
if ptr.is_null() {
None
} else {
Some(unsafe { &*ptr })
}
}
pub fn serialize_extensions<S: serde::Serializer>(
extendee: &str,
fields: &UnknownFields,
serializer: S,
) -> Result<S::Ok, S::Error> {
use serde::ser::{Error, SerializeMap};
let mut map = serializer.serialize_map(None)?;
let Some(reg) = extension_registry() else {
return map.end();
};
if fields.is_empty() {
return map.end();
}
let mut seen: Vec<u32> = Vec::new();
for uf in fields.iter() {
if seen.contains(&uf.number) {
continue;
}
seen.push(uf.number);
if let Some(entry) = reg.by_number(extendee, uf.number) {
let json = (entry.to_json)(uf.number, fields).map_err(S::Error::custom)?;
let key = format!("[{}]", entry.full_name);
map.serialize_entry(&key, &json)?;
}
}
map.end()
}
pub fn deserialize_extension_key(
extendee: &str,
key: &str,
value: serde_json::Value,
) -> Option<Result<Vec<UnknownField>, String>> {
let name = key.strip_prefix('[')?.strip_suffix(']')?;
let Some(entry) = extension_registry().and_then(|r| r.by_name(name)) else {
if crate::json::strict_extension_keys() {
return Some(Err(format!("extension `{name}` not in registry")));
}
return None;
};
if entry.extendee != extendee {
return Some(Err(format!(
"extension `{name}` extends `{}`, not `{extendee}`",
entry.extendee
)));
}
Some((entry.from_json)(value, entry.number))
}
pub fn deserialize_extensions<'de, D: serde::Deserializer<'de>>(
extendee: &'static str,
deserializer: D,
) -> Result<UnknownFields, D::Error> {
use serde::de::{Error, MapAccess, Visitor};
struct V {
extendee: &'static str,
}
impl<'de> Visitor<'de> for V {
type Value = UnknownFields;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.write_str("extension map")
}
fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<UnknownFields, M::Error> {
let mut out = UnknownFields::new();
while let Some(key) = map.next_key::<String>()? {
let value: serde_json::Value = map.next_value()?;
match deserialize_extension_key(self.extendee, &key, value) {
Some(Ok(records)) => {
for r in records {
out.push(r);
}
}
Some(Err(e)) => return Err(M::Error::custom(e)),
None => {} }
}
Ok(out)
}
}
deserializer.deserialize_map(V { extendee })
}
pub mod helpers {
use super::*;
use crate::extension::codecs::*;
use crate::extension::ExtensionCodec;
use crate::unknown_fields::{UnknownField, UnknownFieldData};
fn missing(n: u32) -> String {
format!("extension field {n}: no value present")
}
fn json_int<T>(
v: serde_json::Value,
n: u32,
encode: fn(T) -> u64,
) -> Result<Vec<UnknownField>, String>
where
T: TryFrom<i64> + core::str::FromStr,
T::Error: core::fmt::Display,
<T as core::str::FromStr>::Err: core::fmt::Display,
{
let i: T = match v {
serde_json::Value::Number(num) => {
let x = num
.as_i64()
.ok_or_else(|| format!("field {n}: not an integer"))?;
T::try_from(x).map_err(|e| format!("field {n}: {e}"))?
}
serde_json::Value::String(s) => s.parse().map_err(|e| format!("field {n}: {e}"))?,
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Varint(encode(i)),
}])
}
fn json_uint<T>(
v: serde_json::Value,
n: u32,
encode: fn(T) -> u64,
) -> Result<Vec<UnknownField>, String>
where
T: TryFrom<u64> + core::str::FromStr,
T::Error: core::fmt::Display,
<T as core::str::FromStr>::Err: core::fmt::Display,
{
let i: T = match v {
serde_json::Value::Number(num) => {
let x = num
.as_u64()
.ok_or_else(|| format!("field {n}: not an unsigned integer"))?;
T::try_from(x).map_err(|e| format!("field {n}: {e}"))?
}
serde_json::Value::String(s) => s.parse().map_err(|e| format!("field {n}: {e}"))?,
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Varint(encode(i)),
}])
}
pub fn int32_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Int32::decode(n, f)
.map(|v| serde_json::json!(v))
.ok_or_else(|| missing(n))
}
pub fn int32_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
json_int::<i32>(v, n, |v| v as i64 as u64)
}
pub fn sint32_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Sint32::decode(n, f)
.map(|v| serde_json::json!(v))
.ok_or_else(|| missing(n))
}
pub fn sint32_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
json_int::<i32>(v, n, |v| crate::types::zigzag_encode_i32(v) as u64)
}
pub fn uint32_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Uint32::decode(n, f)
.map(|v| serde_json::json!(v))
.ok_or_else(|| missing(n))
}
pub fn uint32_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
json_uint::<u32>(v, n, |v| v as u64)
}
pub fn sfixed32_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Sfixed32::decode(n, f)
.map(|v| serde_json::json!(v))
.ok_or_else(|| missing(n))
}
pub fn sfixed32_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let i: i32 = match v {
serde_json::Value::Number(num) => num
.as_i64()
.and_then(|x| i32::try_from(x).ok())
.ok_or_else(|| format!("field {n}: not an i32"))?,
serde_json::Value::String(s) => s.parse().map_err(|e| format!("field {n}: {e}"))?,
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Fixed32(i as u32),
}])
}
pub fn fixed32_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Fixed32::decode(n, f)
.map(|v| serde_json::json!(v))
.ok_or_else(|| missing(n))
}
pub fn fixed32_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let i: u32 = match v {
serde_json::Value::Number(num) => num
.as_u64()
.and_then(|x| u32::try_from(x).ok())
.ok_or_else(|| format!("field {n}: not a u32"))?,
serde_json::Value::String(s) => s.parse().map_err(|e| format!("field {n}: {e}"))?,
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Fixed32(i),
}])
}
pub fn int64_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Int64::decode(n, f)
.map(|v| serde_json::Value::String(alloc::format!("{v}")))
.ok_or_else(|| missing(n))
}
pub fn int64_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
json_int::<i64>(v, n, |v| v as u64)
}
pub fn sint64_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Sint64::decode(n, f)
.map(|v| serde_json::Value::String(alloc::format!("{v}")))
.ok_or_else(|| missing(n))
}
pub fn sint64_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
json_int::<i64>(v, n, crate::types::zigzag_encode_i64)
}
pub fn uint64_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Uint64::decode(n, f)
.map(|v| serde_json::Value::String(alloc::format!("{v}")))
.ok_or_else(|| missing(n))
}
pub fn uint64_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
json_uint::<u64>(v, n, |v| v)
}
pub fn sfixed64_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Sfixed64::decode(n, f)
.map(|v| serde_json::Value::String(alloc::format!("{v}")))
.ok_or_else(|| missing(n))
}
pub fn sfixed64_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let i: i64 = match v {
serde_json::Value::Number(num) => num
.as_i64()
.ok_or_else(|| format!("field {n}: not an i64"))?,
serde_json::Value::String(s) => s.parse().map_err(|e| format!("field {n}: {e}"))?,
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Fixed64(i as u64),
}])
}
pub fn fixed64_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Fixed64::decode(n, f)
.map(|v| serde_json::Value::String(alloc::format!("{v}")))
.ok_or_else(|| missing(n))
}
pub fn fixed64_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let i: u64 = match v {
serde_json::Value::Number(num) => num
.as_u64()
.ok_or_else(|| format!("field {n}: not a u64"))?,
serde_json::Value::String(s) => s.parse().map_err(|e| format!("field {n}: {e}"))?,
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Fixed64(i),
}])
}
pub fn bool_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Bool::decode(n, f)
.map(serde_json::Value::Bool)
.ok_or_else(|| missing(n))
}
pub fn bool_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let b = v
.as_bool()
.ok_or_else(|| format!("field {n}: expected bool"))?;
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Varint(b as u64),
}])
}
pub fn string_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
StringCodec::decode(n, f)
.map(serde_json::Value::String)
.ok_or_else(|| missing(n))
}
pub fn string_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let serde_json::Value::String(s) = v else {
return Err(format!("field {n}: expected string"));
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::LengthDelimited(s.into_bytes()),
}])
}
pub fn bytes_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
use base64::Engine;
BytesCodec::decode(n, f)
.map(|b| serde_json::Value::String(base64::engine::general_purpose::STANDARD.encode(b)))
.ok_or_else(|| missing(n))
}
pub fn bytes_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
use base64::Engine;
let serde_json::Value::String(s) = v else {
return Err(format!("field {n}: expected base64 string"));
};
let bytes = base64::engine::general_purpose::STANDARD
.decode(s)
.map_err(|e| format!("field {n}: base64: {e}"))?;
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::LengthDelimited(bytes),
}])
}
pub fn float_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Float::decode(n, f)
.map(|v| {
if v.is_nan() {
serde_json::Value::String("NaN".into())
} else if v == f32::INFINITY {
serde_json::Value::String("Infinity".into())
} else if v == f32::NEG_INFINITY {
serde_json::Value::String("-Infinity".into())
} else {
serde_json::json!(v)
}
})
.ok_or_else(|| missing(n))
}
pub fn float_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let f: f32 = match v {
serde_json::Value::Number(num) => {
num.as_f64()
.ok_or_else(|| format!("field {n}: not a number"))? as f32
}
serde_json::Value::String(s) => match s.as_str() {
"NaN" => f32::NAN,
"Infinity" => f32::INFINITY,
"-Infinity" => f32::NEG_INFINITY,
_ => s.parse().map_err(|e| format!("field {n}: {e}"))?,
},
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Fixed32(f.to_bits()),
}])
}
pub fn double_to_json(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
Double::decode(n, f)
.map(|v| {
if v.is_nan() {
serde_json::Value::String("NaN".into())
} else if v == f64::INFINITY {
serde_json::Value::String("Infinity".into())
} else if v == f64::NEG_INFINITY {
serde_json::Value::String("-Infinity".into())
} else {
serde_json::json!(v)
}
})
.ok_or_else(|| missing(n))
}
pub fn double_from_json(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
let f: f64 = match v {
serde_json::Value::Number(num) => num
.as_f64()
.ok_or_else(|| format!("field {n}: not a number"))?,
serde_json::Value::String(s) => match s.as_str() {
"NaN" => f64::NAN,
"Infinity" => f64::INFINITY,
"-Infinity" => f64::NEG_INFINITY,
_ => s.parse().map_err(|e| format!("field {n}: {e}"))?,
},
_ => return Err(format!("field {n}: expected number or string")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Fixed64(f.to_bits()),
}])
}
pub fn enum_to_json<E: crate::Enumeration>(
n: u32,
f: &UnknownFields,
) -> Result<serde_json::Value, String> {
let i = Int32::decode(n, f).ok_or_else(|| missing(n))?;
Ok(match E::from_i32(i) {
Some(e) => serde_json::Value::String(e.proto_name().into()),
None => serde_json::json!(i),
})
}
pub fn enum_from_json<E: crate::Enumeration>(
v: serde_json::Value,
n: u32,
) -> Result<Vec<UnknownField>, String> {
let i = match v {
serde_json::Value::String(s) => E::from_proto_name(&s)
.map(|e| e.to_i32())
.ok_or_else(|| format!("field {n}: unknown enum variant `{s}`"))?,
serde_json::Value::Number(num) => num
.as_i64()
.and_then(|x| i32::try_from(x).ok())
.ok_or_else(|| format!("field {n}: not an i32"))?,
_ => return Err(format!("field {n}: expected string or number")),
};
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::Varint(i as i64 as u64),
}])
}
pub fn message_to_json<M>(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String>
where
M: crate::Message + Default + serde::Serialize,
{
let m = MessageCodec::<M>::decode(n, f).ok_or_else(|| missing(n))?;
serde_json::to_value(&m).map_err(|e| alloc::format!("field {n}: {e}"))
}
pub fn message_from_json<M>(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String>
where
M: crate::Message + Default + for<'de> serde::Deserialize<'de>,
{
let m: M = serde_json::from_value(v).map_err(|e| alloc::format!("field {n}: {e}"))?;
Ok(alloc::vec![UnknownField {
number: n,
data: UnknownFieldData::LengthDelimited(m.encode_to_vec()),
}])
}
fn repeated_from_array(
v: serde_json::Value,
n: u32,
from_one: fn(serde_json::Value, u32) -> Result<Vec<UnknownField>, String>,
) -> Result<Vec<UnknownField>, String> {
let serde_json::Value::Array(arr) = v else {
return Err(format!("field {n}: expected array"));
};
let mut out = Vec::with_capacity(arr.len());
for elem in arr {
out.extend(from_one(elem, n)?);
}
Ok(out)
}
macro_rules! repeated_scalar {
($to_name:ident, $from_name:ident, $codec:ty, $to_elem:expr, $from_one:path) => {
pub fn $to_name(n: u32, f: &UnknownFields) -> Result<serde_json::Value, String> {
let vs = Repeated::<$codec>::decode(n, f);
Ok(serde_json::Value::Array(
vs.into_iter().map($to_elem).collect(),
))
}
pub fn $from_name(v: serde_json::Value, n: u32) -> Result<Vec<UnknownField>, String> {
repeated_from_array(v, n, $from_one)
}
};
}
fn f32_to_value(v: f32) -> serde_json::Value {
if v.is_nan() {
serde_json::Value::String("NaN".into())
} else if v == f32::INFINITY {
serde_json::Value::String("Infinity".into())
} else if v == f32::NEG_INFINITY {
serde_json::Value::String("-Infinity".into())
} else {
serde_json::json!(v)
}
}
fn f64_to_value(v: f64) -> serde_json::Value {
if v.is_nan() {
serde_json::Value::String("NaN".into())
} else if v == f64::INFINITY {
serde_json::Value::String("Infinity".into())
} else if v == f64::NEG_INFINITY {
serde_json::Value::String("-Infinity".into())
} else {
serde_json::json!(v)
}
}
repeated_scalar!(
repeated_int32_to_json,
repeated_int32_from_json,
Int32,
|v| serde_json::json!(v),
int32_from_json
);
repeated_scalar!(
repeated_sint32_to_json,
repeated_sint32_from_json,
Sint32,
|v| serde_json::json!(v),
sint32_from_json
);
repeated_scalar!(
repeated_uint32_to_json,
repeated_uint32_from_json,
Uint32,
|v| serde_json::json!(v),
uint32_from_json
);
repeated_scalar!(
repeated_sfixed32_to_json,
repeated_sfixed32_from_json,
Sfixed32,
|v| serde_json::json!(v),
sfixed32_from_json
);
repeated_scalar!(
repeated_fixed32_to_json,
repeated_fixed32_from_json,
Fixed32,
|v| serde_json::json!(v),
fixed32_from_json
);
repeated_scalar!(
repeated_int64_to_json,
repeated_int64_from_json,
Int64,
|v| serde_json::Value::String(alloc::format!("{v}")),
int64_from_json
);
repeated_scalar!(
repeated_sint64_to_json,
repeated_sint64_from_json,
Sint64,
|v| serde_json::Value::String(alloc::format!("{v}")),
sint64_from_json
);
repeated_scalar!(
repeated_uint64_to_json,
repeated_uint64_from_json,
Uint64,
|v| serde_json::Value::String(alloc::format!("{v}")),
uint64_from_json
);
repeated_scalar!(
repeated_sfixed64_to_json,
repeated_sfixed64_from_json,
Sfixed64,
|v| serde_json::Value::String(alloc::format!("{v}")),
sfixed64_from_json
);
repeated_scalar!(
repeated_fixed64_to_json,
repeated_fixed64_from_json,
Fixed64,
|v| serde_json::Value::String(alloc::format!("{v}")),
fixed64_from_json
);
repeated_scalar!(
repeated_bool_to_json,
repeated_bool_from_json,
Bool,
serde_json::Value::Bool,
bool_from_json
);
repeated_scalar!(
repeated_string_to_json,
repeated_string_from_json,
StringCodec,
serde_json::Value::String,
string_from_json
);
repeated_scalar!(
repeated_bytes_to_json,
repeated_bytes_from_json,
BytesCodec,
|b| {
use base64::Engine;
serde_json::Value::String(base64::engine::general_purpose::STANDARD.encode(b))
},
bytes_from_json
);
repeated_scalar!(
repeated_float_to_json,
repeated_float_from_json,
Float,
f32_to_value,
float_from_json
);
repeated_scalar!(
repeated_double_to_json,
repeated_double_from_json,
Double,
f64_to_value,
double_from_json
);
pub fn repeated_enum_to_json<E: crate::Enumeration>(
n: u32,
f: &UnknownFields,
) -> Result<serde_json::Value, String> {
let vs = Repeated::<EnumI32>::decode(n, f);
Ok(serde_json::Value::Array(
vs.into_iter()
.map(|i| match E::from_i32(i) {
Some(e) => serde_json::Value::String(e.proto_name().into()),
None => serde_json::json!(i),
})
.collect(),
))
}
pub fn repeated_enum_from_json<E: crate::Enumeration>(
v: serde_json::Value,
n: u32,
) -> Result<Vec<UnknownField>, String> {
repeated_from_array(v, n, enum_from_json::<E>)
}
pub fn repeated_message_to_json<M>(
n: u32,
f: &UnknownFields,
) -> Result<serde_json::Value, String>
where
M: crate::Message + Default + serde::Serialize,
{
let ms = Repeated::<MessageCodec<M>>::decode(n, f);
let mut arr = Vec::with_capacity(ms.len());
for m in ms {
arr.push(serde_json::to_value(&m).map_err(|e| alloc::format!("field {n}: {e}"))?);
}
Ok(serde_json::Value::Array(arr))
}
pub fn repeated_message_from_json<M>(
v: serde_json::Value,
n: u32,
) -> Result<Vec<UnknownField>, String>
where
M: crate::Message + Default + for<'de> serde::Deserialize<'de>,
{
repeated_from_array(v, n, message_from_json::<M>)
}
}
#[cfg(test)]
mod tests {
#![allow(deprecated)]
use super::helpers::*;
use super::*;
use crate::unknown_fields::{UnknownField, UnknownFieldData};
use alloc::vec;
fn fields_with(uf: UnknownField) -> UnknownFields {
let mut f = UnknownFields::new();
f.push(uf);
f
}
macro_rules! entry {
($num:expr, $name:expr, $ext:expr) => {
JsonExtEntry {
number: $num,
full_name: $name,
extendee: $ext,
to_json: int32_to_json,
from_json: int32_from_json,
}
};
}
#[test]
fn int32_roundtrip() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint(42),
});
let json = int32_to_json(1, &f).unwrap();
assert_eq!(json, serde_json::json!(42));
let back = int32_from_json(json, 1).unwrap();
assert_eq!(back.len(), 1);
assert_eq!(back[0].data, UnknownFieldData::Varint(42));
}
#[test]
fn int32_from_string() {
let back = int32_from_json(serde_json::json!("42"), 1).unwrap();
assert_eq!(back[0].data, UnknownFieldData::Varint(42));
}
#[test]
fn int32_negative_sign_extends() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint((-7_i64) as u64),
});
let json = int32_to_json(1, &f).unwrap();
assert_eq!(json, serde_json::json!(-7));
let back = int32_from_json(json, 1).unwrap();
assert_eq!(back[0].data, UnknownFieldData::Varint((-7_i64) as u64));
}
#[test]
fn int64_stringifies() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint(9_999_999_999),
});
let json = int64_to_json(1, &f).unwrap();
assert_eq!(json, serde_json::json!("9999999999"));
let back = int64_from_json(json, 1).unwrap();
assert_eq!(back[0].data, UnknownFieldData::Varint(9_999_999_999));
}
#[test]
fn sint32_zigzag_roundtrip() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint(1),
});
let json = sint32_to_json(1, &f).unwrap();
assert_eq!(json, serde_json::json!(-1));
let back = sint32_from_json(json, 1).unwrap();
assert_eq!(back[0].data, UnknownFieldData::Varint(1));
}
#[test]
fn bool_roundtrip() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint(1),
});
assert_eq!(bool_to_json(1, &f).unwrap(), serde_json::json!(true));
let back = bool_from_json(serde_json::json!(false), 1).unwrap();
assert_eq!(back[0].data, UnknownFieldData::Varint(0));
}
#[test]
fn string_roundtrip() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::LengthDelimited(b"hello".to_vec()),
});
assert_eq!(string_to_json(1, &f).unwrap(), serde_json::json!("hello"));
let back = string_from_json(serde_json::json!("world"), 1).unwrap();
assert_eq!(
back[0].data,
UnknownFieldData::LengthDelimited(b"world".to_vec())
);
}
#[test]
fn bytes_base64_roundtrip() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::LengthDelimited(vec![0xDE, 0xAD, 0xBE, 0xEF]),
});
let json = bytes_to_json(1, &f).unwrap();
assert_eq!(json, serde_json::json!("3q2+7w=="));
let back = bytes_from_json(json, 1).unwrap();
assert_eq!(
back[0].data,
UnknownFieldData::LengthDelimited(vec![0xDE, 0xAD, 0xBE, 0xEF])
);
}
#[test]
fn float_special_values() {
for (bits, expected) in [
(f32::NAN.to_bits(), "NaN"),
(f32::INFINITY.to_bits(), "Infinity"),
(f32::NEG_INFINITY.to_bits(), "-Infinity"),
] {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Fixed32(bits),
});
assert_eq!(float_to_json(1, &f).unwrap(), serde_json::json!(expected));
}
let back = float_from_json(serde_json::json!("NaN"), 1).unwrap();
let UnknownFieldData::Fixed32(b) = back[0].data else {
panic!()
};
assert!(f32::from_bits(b).is_nan());
}
#[test]
fn registry_lookup_both_axes() {
let mut reg = ExtensionRegistry::new();
reg.register(entry!(120, "pkg.ext", "pkg.Msg"));
assert!(reg.by_number("pkg.Msg", 120).is_some());
assert!(reg.by_number("pkg.Msg", 999).is_none());
assert!(reg.by_number("other.Msg", 120).is_none());
assert_eq!(reg.by_name("pkg.ext").unwrap().number, 120);
assert!(reg.by_name("pkg.nonexistent").is_none());
}
#[test]
fn deserialize_extension_key_shapes() {
let mut reg = ExtensionRegistry::new();
reg.register(entry!(120, "pkg.ext", "pkg.Msg"));
set_extension_registry(Box::new(reg));
assert!(
deserialize_extension_key("pkg.Msg", "regular_key", serde_json::json!(1)).is_none()
);
let result =
deserialize_extension_key("pkg.Msg", "[pkg.ext]", serde_json::json!(42)).unwrap();
assert_eq!(result.unwrap()[0].data, UnknownFieldData::Varint(42));
let result =
deserialize_extension_key("other.Msg", "[pkg.ext]", serde_json::json!(1)).unwrap();
assert!(result.is_err());
assert!(
deserialize_extension_key("pkg.Msg", "[pkg.missing]", serde_json::json!(1)).is_none()
);
}
#[test]
#[cfg(feature = "std")]
fn deserialize_extension_key_strict_mode() {
use crate::json::{with_json_parse_options, JsonParseOptions};
let mut reg = ExtensionRegistry::new();
reg.register(entry!(120, "pkg.ext", "pkg.Msg"));
set_extension_registry(Box::new(reg));
let strict = JsonParseOptions::new().strict_extension_keys(true);
with_json_parse_options(&strict, || {
let result =
deserialize_extension_key("pkg.Msg", "[pkg.missing]", serde_json::json!(1));
let err = result.expect("Some in strict mode").unwrap_err();
assert!(err.contains("not in registry"), "{err}");
assert!(
deserialize_extension_key("pkg.Msg", "plain_key", serde_json::json!(1)).is_none()
);
let result = deserialize_extension_key("pkg.Msg", "[pkg.ext]", serde_json::json!(42));
assert_eq!(
result.unwrap().unwrap()[0].data,
UnknownFieldData::Varint(42)
);
});
assert!(
deserialize_extension_key("pkg.Msg", "[pkg.missing]", serde_json::json!(1)).is_none()
);
}
#[test]
fn serialize_extensions_via_registry() {
let mut reg = ExtensionRegistry::new();
reg.register(entry!(50, "pkg.weight", "pkg.Carrier"));
set_extension_registry(Box::new(reg));
let mut fields = UnknownFields::new();
fields.push(UnknownField {
number: 50,
data: UnknownFieldData::Varint(7),
});
fields.push(UnknownField {
number: 99,
data: UnknownFieldData::Varint(0),
});
let json = serde_json::to_value(SerWrap {
extendee: "pkg.Carrier",
fields: &fields,
})
.unwrap();
assert_eq!(json, serde_json::json!({"[pkg.weight]": 7}));
}
struct SerWrap<'a> {
extendee: &'static str,
fields: &'a UnknownFields,
}
impl serde::Serialize for SerWrap<'_> {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_extensions(self.extendee, self.fields, s)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
enum Color {
Red = 0,
Green = 1,
Blue = 2,
}
impl crate::Enumeration for Color {
fn from_i32(v: i32) -> Option<Self> {
match v {
0 => Some(Color::Red),
1 => Some(Color::Green),
2 => Some(Color::Blue),
_ => None,
}
}
fn to_i32(&self) -> i32 {
*self as i32
}
fn proto_name(&self) -> &'static str {
match self {
Color::Red => "RED",
Color::Green => "GREEN",
Color::Blue => "BLUE",
}
}
fn from_proto_name(name: &str) -> Option<Self> {
match name {
"RED" => Some(Color::Red),
"GREEN" => Some(Color::Green),
"BLUE" => Some(Color::Blue),
_ => None,
}
}
}
#[test]
fn enum_to_json_known_variant_emits_name() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint(1), });
assert_eq!(
enum_to_json::<Color>(1, &f).unwrap(),
serde_json::json!("GREEN")
);
}
#[test]
fn enum_to_json_unknown_falls_back_to_numeric() {
let f = fields_with(UnknownField {
number: 1,
data: UnknownFieldData::Varint(99),
});
assert_eq!(enum_to_json::<Color>(1, &f).unwrap(), serde_json::json!(99));
}
#[test]
fn enum_from_json_accepts_name_and_number() {
let by_name = enum_from_json::<Color>(serde_json::json!("BLUE"), 1).unwrap();
assert_eq!(by_name[0].data, UnknownFieldData::Varint(2));
let by_num = enum_from_json::<Color>(serde_json::json!(1), 1).unwrap();
assert_eq!(by_num[0].data, UnknownFieldData::Varint(1));
}
#[test]
fn enum_from_json_unknown_name_errors() {
let err = enum_from_json::<Color>(serde_json::json!("PURPLE"), 1).unwrap_err();
assert!(err.contains("unknown enum variant"), "{err}");
}
fn fields_from(records: Vec<UnknownField>) -> UnknownFields {
let mut f = UnknownFields::new();
for r in records {
f.push(r);
}
f
}
#[test]
fn repeated_int32_roundtrip() {
let json = serde_json::json!([1, -2, 3]);
let records = repeated_int32_from_json(json.clone(), 5).unwrap();
assert_eq!(records.len(), 3);
let f = fields_from(records);
assert_eq!(repeated_int32_to_json(5, &f).unwrap(), json);
}
#[test]
fn repeated_int64_stringifies_elements() {
let records = repeated_int64_from_json(serde_json::json!(["7", 8]), 5).unwrap();
let f = fields_from(records);
assert_eq!(
repeated_int64_to_json(5, &f).unwrap(),
serde_json::json!(["7", "8"])
);
}
#[test]
fn repeated_string_roundtrip() {
let json = serde_json::json!(["a", "b", "c"]);
let records = repeated_string_from_json(json.clone(), 5).unwrap();
let f = fields_from(records);
assert_eq!(repeated_string_to_json(5, &f).unwrap(), json);
}
#[test]
fn repeated_from_json_rejects_non_array() {
let err = repeated_int32_from_json(serde_json::json!(42), 5).unwrap_err();
assert!(err.contains("expected array"), "{err}");
}
#[test]
fn repeated_enum_roundtrip() {
let json = serde_json::json!(["RED", "BLUE"]);
let records = repeated_enum_from_json::<Color>(json.clone(), 5).unwrap();
assert_eq!(records.len(), 2);
let f = fields_from(records);
assert_eq!(repeated_enum_to_json::<Color>(5, &f).unwrap(), json);
}
#[test]
fn repeated_to_json_empty_when_no_records() {
let f = UnknownFields::new();
assert_eq!(
repeated_int32_to_json(5, &f).unwrap(),
serde_json::json!([])
);
}
#[test]
fn enum_helpers_satisfy_fn_pointer_signature() {
let _: fn(u32, &UnknownFields) -> Result<serde_json::Value, String> = enum_to_json::<Color>;
let _: fn(serde_json::Value, u32) -> Result<Vec<UnknownField>, String> =
enum_from_json::<Color>;
let _: fn(u32, &UnknownFields) -> Result<serde_json::Value, String> =
repeated_enum_to_json::<Color>;
}
}