| use std::fmt; |
| use std::fmt::Write as fmt_Write; |
| |
| use protobuf::reflect::EnumDescriptor; |
| use protobuf::reflect::EnumValueDescriptor; |
| use protobuf::reflect::MessageRef; |
| use protobuf::reflect::ReflectFieldRef; |
| use protobuf::reflect::ReflectMapRef; |
| use protobuf::reflect::ReflectRepeatedRef; |
| use protobuf::reflect::ReflectValueRef; |
| use protobuf::reflect::RuntimeFieldType; |
| use protobuf::reflect::RuntimeType; |
| use protobuf::well_known_types::any::Any; |
| use protobuf::well_known_types::duration::Duration; |
| use protobuf::well_known_types::field_mask::FieldMask; |
| use protobuf::well_known_types::struct_::value; |
| use protobuf::well_known_types::struct_::ListValue; |
| use protobuf::well_known_types::struct_::NullValue; |
| use protobuf::well_known_types::struct_::Struct; |
| use protobuf::well_known_types::struct_::Value; |
| use protobuf::well_known_types::timestamp::Timestamp; |
| use protobuf::well_known_types::wrappers::BoolValue; |
| use protobuf::well_known_types::wrappers::BytesValue; |
| use protobuf::well_known_types::wrappers::DoubleValue; |
| use protobuf::well_known_types::wrappers::FloatValue; |
| use protobuf::well_known_types::wrappers::Int32Value; |
| use protobuf::well_known_types::wrappers::Int64Value; |
| use protobuf::well_known_types::wrappers::StringValue; |
| use protobuf::well_known_types::wrappers::UInt32Value; |
| use protobuf::well_known_types::wrappers::UInt64Value; |
| use protobuf::MessageDyn; |
| |
| use crate::base64; |
| use crate::float; |
| use crate::rfc_3339::TmUtc; |
| use crate::well_known_wrapper::WellKnownWrapper; |
| |
| #[derive(Debug, thiserror::Error)] |
| enum PrintErrorInner { |
| #[error(transparent)] |
| Fmt(fmt::Error), |
| #[error("JSON printing of Any is not implemented")] |
| AnyPrintingIsNotImplemented, |
| #[error("Negative nanoseconds in timestamp")] |
| TimestampNegativeNanos, |
| #[error("Unknown struct value kind")] |
| UnknownStructValueKind, |
| } |
| |
| /// Print to JSON error. |
| #[derive(Debug, thiserror::Error)] |
| #[error(transparent)] |
| pub struct PrintError(PrintErrorInner); |
| |
| impl From<fmt::Error> for PrintError { |
| fn from(e: fmt::Error) -> Self { |
| PrintError(PrintErrorInner::Fmt(e)) |
| } |
| } |
| |
| pub type PrintResult<T> = Result<T, PrintError>; |
| |
| struct Printer { |
| buf: String, |
| print_options: PrintOptions, |
| } |
| |
| trait PrintableToJson { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()>; |
| } |
| |
| trait JsonFloat: fmt::Display + fmt::Debug + PrintableToJson { |
| fn is_nan(&self) -> bool; |
| fn is_pos_infinity(&self) -> bool; |
| fn is_neg_infinity(&self) -> bool; |
| |
| fn print_to_json_impl(&self, w: &mut String) -> PrintResult<()> { |
| Ok(if self.is_nan() { |
| write!(w, "\"{}\"", float::PROTOBUF_JSON_NAN)? |
| } else if self.is_pos_infinity() { |
| write!(w, "\"{}\"", float::PROTOBUF_JSON_INF)? |
| } else if self.is_neg_infinity() { |
| write!(w, "\"{}\"", float::PROTOBUF_JSON_MINUS_INF)? |
| } else { |
| write!(w, "{:?}", self)? |
| }) |
| } |
| } |
| |
| impl JsonFloat for f32 { |
| fn is_nan(&self) -> bool { |
| f32::is_nan(*self) |
| } |
| |
| fn is_pos_infinity(&self) -> bool { |
| f32::is_infinite(*self) && self > &0.0 |
| } |
| |
| fn is_neg_infinity(&self) -> bool { |
| f32::is_infinite(*self) && self < &0.0 |
| } |
| } |
| |
| impl PrintableToJson for f32 { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| Ok(self.print_to_json_impl(&mut w.buf)?) |
| } |
| } |
| |
| impl JsonFloat for f64 { |
| fn is_nan(&self) -> bool { |
| f64::is_nan(*self) |
| } |
| |
| fn is_pos_infinity(&self) -> bool { |
| f64::is_infinite(*self) && self > &0.0 |
| } |
| |
| fn is_neg_infinity(&self) -> bool { |
| f64::is_infinite(*self) && self < &0.0 |
| } |
| } |
| |
| impl PrintableToJson for f64 { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| self.print_to_json_impl(&mut w.buf) |
| } |
| } |
| |
| impl PrintableToJson for u64 { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| // 64-bit integers are quoted by default |
| Ok(write!(w.buf, "\"{}\"", self)?) |
| } |
| } |
| |
| impl PrintableToJson for i64 { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| // 64-bit integers are quoted by default |
| Ok(write!(w.buf, "\"{}\"", self)?) |
| } |
| } |
| |
| impl PrintableToJson for u32 { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| Ok(write!(w.buf, "{}", self)?) |
| } |
| } |
| |
| impl PrintableToJson for i32 { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| Ok(write!(w.buf, "{}", self)?) |
| } |
| } |
| |
| impl PrintableToJson for bool { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| Ok(write!(w.buf, "{}", self)?) |
| } |
| } |
| |
| impl PrintableToJson for str { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| write!(w.buf, "\"")?; |
| for c in self.chars() { |
| match c { |
| '"' => write!(w.buf, "\\\""), |
| '\\' => write!(w.buf, "\\\\"), |
| '\n' => write!(w.buf, "\\n"), |
| '\r' => write!(w.buf, "\\r"), |
| '\t' => write!(w.buf, "\\t"), |
| c if c.is_control() => write!(w.buf, "\\u{:04x}", c as u32), |
| c => write!(w.buf, "{}", c), |
| }?; |
| } |
| write!(w.buf, "\"")?; |
| Ok(()) |
| } |
| } |
| |
| impl PrintableToJson for String { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| self.as_str().print_to_json(w) |
| } |
| } |
| |
| impl PrintableToJson for [u8] { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| let encoded = base64::encode(self); |
| encoded.print_to_json(w) |
| } |
| } |
| |
| impl PrintableToJson for Vec<u8> { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| self.as_slice().print_to_json(w) |
| } |
| } |
| |
| impl<'a> PrintableToJson for ReflectValueRef<'a> { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| match self { |
| ReflectValueRef::U32(v) => w.print_printable(v), |
| ReflectValueRef::U64(v) => w.print_printable(v), |
| ReflectValueRef::I32(v) => w.print_printable(v), |
| ReflectValueRef::I64(v) => w.print_printable(v), |
| ReflectValueRef::F32(v) => w.print_printable(v), |
| ReflectValueRef::F64(v) => w.print_printable(v), |
| ReflectValueRef::Bool(v) => w.print_printable(v), |
| ReflectValueRef::String(v) => w.print_printable::<str>(v), |
| ReflectValueRef::Bytes(v) => w.print_printable::<[u8]>(v), |
| ReflectValueRef::Enum(d, v) => w.print_enum(d, *v), |
| ReflectValueRef::Message(v) => w.print_message(v), |
| } |
| } |
| } |
| |
| impl PrintableToJson for Duration { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| let sign = if self.seconds >= 0 { "" } else { "-" }; |
| Ok(write!( |
| w.buf, |
| "\"{}{}.{:09}s\"", |
| sign, |
| self.seconds.abs(), |
| self.nanos.abs() |
| )?) |
| } |
| } |
| |
| impl PrintableToJson for Timestamp { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| if self.nanos < 0 { |
| return Err(PrintError(PrintErrorInner::TimestampNegativeNanos)); |
| } |
| let tm_utc = TmUtc::from_protobuf_timestamp(self.seconds, self.nanos as u32); |
| w.print_printable(&tm_utc.to_string()) |
| } |
| } |
| |
| impl PrintableToJson for FieldMask { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| w.print_printable(&self.paths.join(",")) |
| } |
| } |
| |
| impl PrintableToJson for Any { |
| fn print_to_json(&self, _w: &mut Printer) -> PrintResult<()> { |
| Err(PrintError(PrintErrorInner::AnyPrintingIsNotImplemented)) |
| } |
| } |
| |
| impl PrintableToJson for Value { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| match self.kind { |
| // None should not be possible here, but it's better to print null than crash |
| None => w.print_json_null(), |
| Some(value::Kind::NullValue(null_value)) => { |
| match null_value.enum_value() { |
| Ok(value) => w.print_wk_null_value(&value), |
| Err(n) => { |
| // Practically not possible, but it is safer this way. |
| w.print_printable(&n) |
| } |
| } |
| } |
| Some(value::Kind::BoolValue(b)) => w.print_printable(&b), |
| Some(value::Kind::NumberValue(n)) => w.print_printable(&n), |
| Some(value::Kind::StringValue(ref s)) => w.print_printable::<String>(&s), |
| Some(value::Kind::StructValue(ref s)) => w.print_printable(&s), |
| Some(value::Kind::ListValue(ref l)) => w.print_printable(&l), |
| Some(_) => Err(PrintError(PrintErrorInner::UnknownStructValueKind)), |
| } |
| } |
| } |
| |
| impl PrintableToJson for ListValue { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| w.print_list(&self.values) |
| } |
| } |
| |
| impl PrintableToJson for Struct { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| w.print_object(&self.fields) |
| } |
| } |
| |
| impl<'a, P: PrintableToJson> PrintableToJson for &'a P { |
| fn print_to_json(&self, w: &mut Printer) -> PrintResult<()> { |
| (*self).print_to_json(w) |
| } |
| } |
| |
| trait ObjectKey { |
| fn print_object_key(&self, w: &mut Printer) -> PrintResult<()>; |
| } |
| |
| impl<'a> ObjectKey for ReflectValueRef<'a> { |
| fn print_object_key(&self, w: &mut Printer) -> PrintResult<()> { |
| match self { |
| ReflectValueRef::String(v) => return w.print_printable::<str>(v), |
| ReflectValueRef::Bytes(v) => return w.print_printable::<[u8]>(v), |
| // do not quote, because printable is quoted |
| ReflectValueRef::U64(v) => return w.print_printable(v), |
| ReflectValueRef::I64(v) => return w.print_printable(v), |
| ReflectValueRef::Enum(d, v) if !w.print_options.enum_values_int => { |
| return w.print_enum(d, *v) |
| } |
| _ => {} |
| } |
| |
| write!(w.buf, "\"")?; |
| |
| match self { |
| ReflectValueRef::U32(v) => w.print_printable(v), |
| ReflectValueRef::I32(v) => w.print_printable(v), |
| ReflectValueRef::Bool(v) => w.print_printable(v), |
| ReflectValueRef::Enum(d, v) if w.print_options.enum_values_int => w.print_enum(d, *v), |
| ReflectValueRef::Enum(..) |
| | ReflectValueRef::U64(_) |
| | ReflectValueRef::I64(_) |
| | ReflectValueRef::String(_) |
| | ReflectValueRef::Bytes(_) => unreachable!(), |
| ReflectValueRef::F32(_) | ReflectValueRef::F64(_) | ReflectValueRef::Message(_) => { |
| panic!("cannot be object key") |
| } |
| }?; |
| |
| write!(w.buf, "\"")?; |
| |
| Ok(()) |
| } |
| } |
| |
| impl ObjectKey for String { |
| fn print_object_key(&self, w: &mut Printer) -> PrintResult<()> { |
| w.print_printable(self) |
| } |
| } |
| |
| impl<'a, O: ObjectKey> ObjectKey for &'a O { |
| fn print_object_key(&self, w: &mut Printer) -> PrintResult<()> { |
| (*self).print_object_key(w) |
| } |
| } |
| |
| impl Printer { |
| fn print_comma_but_first(&mut self, first: &mut bool) -> fmt::Result { |
| if *first { |
| *first = false; |
| Ok(()) |
| } else { |
| write!(self.buf, ", ") |
| } |
| } |
| |
| fn print_json_null(&mut self) -> PrintResult<()> { |
| Ok(write!(self.buf, "null")?) |
| } |
| |
| fn print_printable<F: PrintableToJson + ?Sized>(&mut self, f: &F) -> PrintResult<()> { |
| f.print_to_json(self) |
| } |
| |
| fn print_list<I>(&mut self, items: I) -> PrintResult<()> |
| where |
| I: IntoIterator, |
| I::Item: PrintableToJson, |
| { |
| write!(self.buf, "[")?; |
| for (i, item) in items.into_iter().enumerate() { |
| if i != 0 { |
| write!(self.buf, ", ")?; |
| } |
| self.print_printable(&item)?; |
| } |
| write!(self.buf, "]")?; |
| Ok(()) |
| } |
| |
| fn print_repeated(&mut self, repeated: &ReflectRepeatedRef) -> PrintResult<()> { |
| self.print_list(repeated) |
| } |
| |
| fn print_object<I, K, V>(&mut self, items: I) -> PrintResult<()> |
| where |
| I: IntoIterator<Item = (K, V)>, |
| K: ObjectKey, |
| V: PrintableToJson, |
| { |
| write!(self.buf, "{{")?; |
| for (i, (k, v)) in items.into_iter().enumerate() { |
| if i != 0 { |
| write!(self.buf, ", ")?; |
| } |
| k.print_object_key(self)?; |
| write!(self.buf, ": ")?; |
| self.print_printable(&v)?; |
| } |
| write!(self.buf, "}}")?; |
| Ok(()) |
| } |
| |
| fn print_map(&mut self, map: &ReflectMapRef) -> PrintResult<()> { |
| self.print_object(map.into_iter()) |
| } |
| |
| fn print_enum_known(&mut self, value: &EnumValueDescriptor) -> PrintResult<()> { |
| if let Some(null_value) = value.cast() { |
| self.print_wk_null_value(&null_value) |
| } else { |
| if self.print_options.enum_values_int { |
| self.print_printable(&value.value()) |
| } else { |
| Ok(write!(self.buf, "\"{}\"", value.name())?) |
| } |
| } |
| } |
| |
| fn print_enum(&mut self, descriptor: &EnumDescriptor, v: i32) -> PrintResult<()> { |
| if self.print_options.enum_values_int { |
| self.print_printable(&v) |
| } else { |
| match descriptor.value_by_number(v) { |
| Some(value) => self.print_enum_known(&value), |
| None => self.print_printable(&v), |
| } |
| } |
| } |
| |
| fn print_message(&mut self, message: &MessageRef) -> PrintResult<()> { |
| if let Some(duration) = message.downcast_ref::<Duration>() { |
| self.print_printable(duration) |
| } else if let Some(timestamp) = message.downcast_ref::<Timestamp>() { |
| self.print_printable(timestamp) |
| } else if let Some(field_mask) = message.downcast_ref::<FieldMask>() { |
| self.print_printable(field_mask) |
| } else if let Some(any) = message.downcast_ref::<Any>() { |
| self.print_printable(any) |
| } else if let Some(value) = message.downcast_ref::<Value>() { |
| self.print_printable(value) |
| } else if let Some(value) = message.downcast_ref::<DoubleValue>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<FloatValue>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<Int64Value>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<UInt64Value>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<Int32Value>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<UInt32Value>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<BoolValue>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<StringValue>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<BytesValue>() { |
| self.print_wrapper(value) |
| } else if let Some(value) = message.downcast_ref::<ListValue>() { |
| self.print_printable(value) |
| } else if let Some(value) = message.downcast_ref::<Struct>() { |
| self.print_printable(value) |
| } else { |
| self.print_regular_message(message) |
| } |
| } |
| |
| fn print_regular_message(&mut self, message: &MessageRef) -> Result<(), PrintError> { |
| let descriptor = message.descriptor_dyn(); |
| |
| write!(self.buf, "{{")?; |
| let mut first = true; |
| for field in descriptor.fields() { |
| let json_field_name = if self.print_options.proto_field_name { |
| field.name() |
| } else { |
| field.json_name() |
| }; |
| |
| let field_type = field.runtime_field_type(); |
| |
| match field.get_reflect(&**message) { |
| ReflectFieldRef::Optional(v) => match v.value() { |
| None => { |
| if self.print_options.always_output_default_values { |
| let is_message = match field_type { |
| RuntimeFieldType::Singular(s) => match s { |
| RuntimeType::Message(_) => true, |
| _ => false, |
| }, |
| _ => unreachable!(), |
| }; |
| |
| let is_oneof = field.proto().has_oneof_index(); |
| |
| if !is_message && !is_oneof { |
| let v = field.get_singular_field_or_default(&**message); |
| self.print_comma_but_first(&mut first)?; |
| write!(self.buf, "\"{}\": ", json_field_name)?; |
| self.print_printable(&v)?; |
| } |
| } |
| } |
| Some(v) => { |
| self.print_comma_but_first(&mut first)?; |
| write!(self.buf, "\"{}\": ", json_field_name)?; |
| self.print_printable(&v)?; |
| } |
| }, |
| ReflectFieldRef::Repeated(v) => { |
| if !v.is_empty() || self.print_options.always_output_default_values { |
| self.print_comma_but_first(&mut first)?; |
| write!(self.buf, "\"{}\": ", json_field_name)?; |
| self.print_repeated(&v)?; |
| } |
| } |
| ReflectFieldRef::Map(v) => { |
| if !v.is_empty() || self.print_options.always_output_default_values { |
| self.print_comma_but_first(&mut first)?; |
| write!(self.buf, "\"{}\": ", json_field_name)?; |
| self.print_map(&v)?; |
| } |
| } |
| } |
| } |
| write!(self.buf, "}}")?; |
| Ok(()) |
| } |
| |
| fn print_wk_null_value(&mut self, _null_value: &NullValue) -> PrintResult<()> { |
| self.print_json_null() |
| } |
| |
| fn print_wrapper<W>(&mut self, value: &W) -> PrintResult<()> |
| where |
| W: WellKnownWrapper, |
| W::Underlying: PrintableToJson, |
| { |
| self.print_printable(value.get_ref()) |
| } |
| } |
| |
| /// Options for printing JSON to string |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// let print_options = protobuf_json_mapping::PrintOptions { |
| /// enum_values_int: true, |
| /// ..Default::default() |
| /// }; |
| /// ``` |
| #[derive(Default, Debug, Clone)] |
| pub struct PrintOptions { |
| /// Use ints instead of strings for enums. |
| /// |
| /// Note both string or int can be parsed. |
| pub enum_values_int: bool, |
| /// Use protobuf field names instead of `lowerCamelCase` which is used by default. |
| /// Note both names are supported when JSON is parsed. |
| pub proto_field_name: bool, |
| /// Output field default values. |
| pub always_output_default_values: bool, |
| /// Prevent initializing `PrintOptions` enumerating all field. |
| pub _future_options: (), |
| } |
| |
| /// Serialize message to JSON according to protobuf specification. |
| pub fn print_to_string_with_options( |
| message: &dyn MessageDyn, |
| print_options: &PrintOptions, |
| ) -> PrintResult<String> { |
| let mut printer = Printer { |
| buf: String::new(), |
| print_options: print_options.clone(), |
| }; |
| printer.print_message(&MessageRef::from(message))?; |
| Ok(printer.buf) |
| } |
| |
| /// Serialize message to JSON according to protobuf specification. |
| pub fn print_to_string(message: &dyn MessageDyn) -> PrintResult<String> { |
| print_to_string_with_options(message, &PrintOptions::default()) |
| } |