use crate::lib::*;
pub mod value;
mod ignored_any;
mod impls;
pub use self::ignored_any::IgnoredAny;
#[cfg(all(not(feature = "std"), no_core_error))]
#[doc(no_inline)]
pub use crate::std_error::Error as StdError;
#[cfg(not(any(feature = "std", no_core_error)))]
#[doc(no_inline)]
pub use core::error::Error as StdError;
#[cfg(feature = "std")]
#[doc(no_inline)]
pub use std::error::Error as StdError;
macro_rules! declare_error_trait {
(Error: Sized $(+ $($supertrait:ident)::+)*) => {
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Error` is not satisfied",
)
)]
pub trait Error: Sized $(+ $($supertrait)::+)* {
fn custom<T>(msg: T) -> Self
where
T: Display;
#[cold]
fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self {
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
}
#[cold]
fn invalid_value(unexp: Unexpected, exp: &dyn Expected) -> Self {
Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp))
}
#[cold]
fn invalid_length(len: usize, exp: &dyn Expected) -> Self {
Error::custom(format_args!("invalid length {}, expected {}", len, exp))
}
#[cold]
fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
if expected.is_empty() {
Error::custom(format_args!(
"unknown variant `{}`, there are no variants",
variant
))
} else {
Error::custom(format_args!(
"unknown variant `{}`, expected {}",
variant,
OneOf { names: expected }
))
}
}
#[cold]
fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
if expected.is_empty() {
Error::custom(format_args!(
"unknown field `{}`, there are no fields",
field
))
} else {
Error::custom(format_args!(
"unknown field `{}`, expected {}",
field,
OneOf { names: expected }
))
}
}
#[cold]
fn missing_field(field: &'static str) -> Self {
Error::custom(format_args!("missing field `{}`", field))
}
#[cold]
fn duplicate_field(field: &'static str) -> Self {
Error::custom(format_args!("duplicate field `{}`", field))
}
}
}
}
#[cfg(feature = "std")]
declare_error_trait!(Error: Sized + StdError);
#[cfg(not(feature = "std"))]
declare_error_trait!(Error: Sized + Debug + Display);
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Unexpected<'a> {
Bool(bool),
Unsigned(u64),
Signed(i64),
Float(f64),
Char(char),
Str(&'a str),
Bytes(&'a [u8]),
Unit,
Option,
NewtypeStruct,
Seq,
Map,
Enum,
UnitVariant,
NewtypeVariant,
TupleVariant,
StructVariant,
Other(&'a str),
}
impl<'a> fmt::Display for Unexpected<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
use self::Unexpected::*;
match *self {
Bool(b) => write!(formatter, "boolean `{}`", b),
Unsigned(i) => write!(formatter, "integer `{}`", i),
Signed(i) => write!(formatter, "integer `{}`", i),
Float(f) => write!(formatter, "floating point `{}`", WithDecimalPoint(f)),
Char(c) => write!(formatter, "character `{}`", c),
Str(s) => write!(formatter, "string {:?}", s),
Bytes(_) => formatter.write_str("byte array"),
Unit => formatter.write_str("unit value"),
Option => formatter.write_str("Option value"),
NewtypeStruct => formatter.write_str("newtype struct"),
Seq => formatter.write_str("sequence"),
Map => formatter.write_str("map"),
Enum => formatter.write_str("enum"),
UnitVariant => formatter.write_str("unit variant"),
NewtypeVariant => formatter.write_str("newtype variant"),
TupleVariant => formatter.write_str("tuple variant"),
StructVariant => formatter.write_str("struct variant"),
Other(other) => formatter.write_str(other),
}
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Expected` is not satisfied",
)
)]
pub trait Expected {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
}
impl<'de, T> Expected for T
where
T: Visitor<'de>,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.expecting(formatter)
}
}
impl Expected for &str {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self)
}
}
impl Display for dyn Expected + '_ {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Expected::fmt(self, formatter)
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
// Prevents `serde_core::de::Deserialize` appearing in the error message
// in projects with no direct dependency on serde_core.
message = "the trait bound `{Self}: serde::Deserialize<'de>` is not satisfied",
note = "for local types consider adding `#[derive(serde::Deserialize)]` to your `{Self}` type",
note = "for types from other crates check whether the crate offers a `serde` feature flag",
)
)]
pub trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
#[doc(hidden)]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
*place = tri!(Deserialize::deserialize(deserializer));
Ok(())
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::DeserializeOwned` is not satisfied",
)
)]
pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::DeserializeSeed<'de>` is not satisfied",
)
)]
pub trait DeserializeSeed<'de>: Sized {
type Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>;
}
impl<'de, T> DeserializeSeed<'de> for PhantomData<T>
where
T: Deserialize<'de>,
{
type Value = T;
#[inline]
fn deserialize<D>(self, deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer)
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Deserializer<'de>` is not satisfied",
)
)]
pub trait Deserializer<'de>: Sized {
type Error: Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let _ = visitor;
Err(Error::custom("i128 is not supported"))
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let _ = visitor;
Err(Error::custom("u128 is not supported"))
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_unit_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_enum<V>(
self,
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
#[inline]
fn is_human_readable(&self) -> bool {
true
}
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
#[doc(hidden)]
fn __deserialize_content_v1<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de, Value = crate::private::Content<'de>>,
{
self.deserialize_any(visitor)
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Visitor<'de>` is not satisfied",
)
)]
pub trait Visitor<'de>: Sized {
type Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Bool(v), &self))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_i64(v as i64)
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_i64(v as i64)
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_i64(v as i64)
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Signed(v), &self))
}
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
let mut buf = [0u8; 58];
let mut writer = crate::format::Buf::new(&mut buf);
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
Err(Error::invalid_type(
Unexpected::Other(writer.as_str()),
&self,
))
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_u64(v as u64)
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_u64(v as u64)
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_u64(v as u64)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Unsigned(v), &self))
}
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
let mut buf = [0u8; 57];
let mut writer = crate::format::Buf::new(&mut buf);
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
Err(Error::invalid_type(
Unexpected::Other(writer.as_str()),
&self,
))
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_f64(v as f64)
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Float(v), &self))
}
#[inline]
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_str(v.encode_utf8(&mut [0u8; 4]))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Str(v), &self))
}
#[inline]
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_str(v)
}
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_str(&v)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Bytes(v), &self))
}
#[inline]
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_bytes(v)
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_bytes(&v)
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Option, &self))
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let _ = deserializer;
Err(Error::invalid_type(Unexpected::Option, &self))
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Err(Error::invalid_type(Unexpected::Unit, &self))
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let _ = deserializer;
Err(Error::invalid_type(Unexpected::NewtypeStruct, &self))
}
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let _ = seq;
Err(Error::invalid_type(Unexpected::Seq, &self))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let _ = map;
Err(Error::invalid_type(Unexpected::Map, &self))
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let _ = data;
Err(Error::invalid_type(Unexpected::Enum, &self))
}
#[doc(hidden)]
fn __private_visit_untagged_option<D>(self, _: D) -> Result<Self::Value, ()>
where
D: Deserializer<'de>,
{
Err(())
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::SeqAccess<'de>` is not satisfied",
)
)]
pub trait SeqAccess<'de> {
type Error: Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>;
#[inline]
fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error>
where
T: Deserialize<'de>,
{
self.next_element_seed(PhantomData)
}
#[inline]
fn size_hint(&self) -> Option<usize> {
None
}
}
impl<'de, A> SeqAccess<'de> for &mut A
where
A: ?Sized + SeqAccess<'de>,
{
type Error = A::Error;
#[inline]
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
(**self).next_element_seed(seed)
}
#[inline]
fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error>
where
T: Deserialize<'de>,
{
(**self).next_element()
}
#[inline]
fn size_hint(&self) -> Option<usize> {
(**self).size_hint()
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::MapAccess<'de>` is not satisfied",
)
)]
pub trait MapAccess<'de> {
type Error: Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>;
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>;
#[inline]
fn next_entry_seed<K, V>(
&mut self,
kseed: K,
vseed: V,
) -> Result<Option<(K::Value, V::Value)>, Self::Error>
where
K: DeserializeSeed<'de>,
V: DeserializeSeed<'de>,
{
match tri!(self.next_key_seed(kseed)) {
Some(key) => {
let value = tri!(self.next_value_seed(vseed));
Ok(Some((key, value)))
}
None => Ok(None),
}
}
#[inline]
fn next_key<K>(&mut self) -> Result<Option<K>, Self::Error>
where
K: Deserialize<'de>,
{
self.next_key_seed(PhantomData)
}
#[inline]
fn next_value<V>(&mut self) -> Result<V, Self::Error>
where
V: Deserialize<'de>,
{
self.next_value_seed(PhantomData)
}
#[inline]
fn next_entry<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error>
where
K: Deserialize<'de>,
V: Deserialize<'de>,
{
self.next_entry_seed(PhantomData, PhantomData)
}
#[inline]
fn size_hint(&self) -> Option<usize> {
None
}
}
impl<'de, A> MapAccess<'de> for &mut A
where
A: ?Sized + MapAccess<'de>,
{
type Error = A::Error;
#[inline]
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
(**self).next_key_seed(seed)
}
#[inline]
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
{
(**self).next_value_seed(seed)
}
#[inline]
fn next_entry_seed<K, V>(
&mut self,
kseed: K,
vseed: V,
) -> Result<Option<(K::Value, V::Value)>, Self::Error>
where
K: DeserializeSeed<'de>,
V: DeserializeSeed<'de>,
{
(**self).next_entry_seed(kseed, vseed)
}
#[inline]
fn next_entry<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error>
where
K: Deserialize<'de>,
V: Deserialize<'de>,
{
(**self).next_entry()
}
#[inline]
fn next_key<K>(&mut self) -> Result<Option<K>, Self::Error>
where
K: Deserialize<'de>,
{
(**self).next_key()
}
#[inline]
fn next_value<V>(&mut self) -> Result<V, Self::Error>
where
V: Deserialize<'de>,
{
(**self).next_value()
}
#[inline]
fn size_hint(&self) -> Option<usize> {
(**self).size_hint()
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::EnumAccess<'de>` is not satisfied",
)
)]
pub trait EnumAccess<'de>: Sized {
type Error: Error;
type Variant: VariantAccess<'de, Error = Self::Error>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>;
#[inline]
fn variant<V>(self) -> Result<(V, Self::Variant), Self::Error>
where
V: Deserialize<'de>,
{
self.variant_seed(PhantomData)
}
}
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::VariantAccess<'de>` is not satisfied",
)
)]
pub trait VariantAccess<'de>: Sized {
type Error: Error;
fn unit_variant(self) -> Result<(), Self::Error>;
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>;
#[inline]
fn newtype_variant<T>(self) -> Result<T, Self::Error>
where
T: Deserialize<'de>,
{
self.newtype_variant_seed(PhantomData)
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>;
}
pub trait IntoDeserializer<'de, E: Error = value::Error> {
type Deserializer: Deserializer<'de, Error = E>;
fn into_deserializer(self) -> Self::Deserializer;
}
struct OneOf {
names: &'static [&'static str],
}
impl Display for OneOf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.names.len() {
0 => panic!(), 1 => write!(formatter, "`{}`", self.names[0]),
2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]),
_ => {
tri!(formatter.write_str("one of "));
for (i, alt) in self.names.iter().enumerate() {
if i > 0 {
tri!(formatter.write_str(", "));
}
tri!(write!(formatter, "`{}`", alt));
}
Ok(())
}
}
}
}
struct WithDecimalPoint(f64);
impl Display for WithDecimalPoint {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
struct LookForDecimalPoint<'f, 'a> {
formatter: &'f mut fmt::Formatter<'a>,
has_decimal_point: bool,
}
impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> {
fn write_str(&mut self, fragment: &str) -> fmt::Result {
self.has_decimal_point |= fragment.contains('.');
self.formatter.write_str(fragment)
}
fn write_char(&mut self, ch: char) -> fmt::Result {
self.has_decimal_point |= ch == '.';
self.formatter.write_char(ch)
}
}
if self.0.is_finite() {
let mut writer = LookForDecimalPoint {
formatter,
has_decimal_point: false,
};
tri!(write!(writer, "{}", self.0));
if !writer.has_decimal_point {
tri!(formatter.write_str(".0"));
}
} else {
tri!(write!(formatter, "{}", self.0));
}
Ok(())
}
}