extern crate alloc;
use alloc::string::String;
use core::fmt::Write as FmtWrite;
use facet_core::{Def, ScalarType};
use facet_reflect::Peek;
use super::DomSerializer;
pub trait WriteScalar: DomSerializer {
fn format_scalar(&self, value: Peek<'_, '_>) -> Option<String> {
let value = value.innermost_peek();
if let Def::Option(_) = &value.shape().def
&& let Ok(opt) = value.into_option()
{
return match opt.value() {
Some(inner) => self.format_scalar(inner),
None => None,
};
}
if let Some(scalar_type) = value.scalar_type() {
let mut buf = ScalarBuffer::new();
let written = match scalar_type {
ScalarType::Unit => {
buf.push_str("null");
true
}
ScalarType::Bool => {
if let Ok(b) = value.get::<bool>() {
buf.push_str(if *b { "true" } else { "false" });
true
} else {
false
}
}
ScalarType::Char => {
if let Ok(c) = value.get::<char>() {
buf.push(*c);
true
} else {
false
}
}
ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
if let Some(s) = value.as_str() {
return Some(s.to_string());
}
false
}
ScalarType::F32 => {
if let Ok(v) = value.get::<f32>() {
self.write_float(*v as f64, &mut buf);
true
} else {
false
}
}
ScalarType::F64 => {
if let Ok(v) = value.get::<f64>() {
self.write_float(*v, &mut buf);
true
} else {
false
}
}
ScalarType::U8 => write_int!(buf, value, u8),
ScalarType::U16 => write_int!(buf, value, u16),
ScalarType::U32 => write_int!(buf, value, u32),
ScalarType::U64 => write_int!(buf, value, u64),
ScalarType::U128 => write_int!(buf, value, u128),
ScalarType::USize => write_int!(buf, value, usize),
ScalarType::I8 => write_int!(buf, value, i8),
ScalarType::I16 => write_int!(buf, value, i16),
ScalarType::I32 => write_int!(buf, value, i32),
ScalarType::I64 => write_int!(buf, value, i64),
ScalarType::I128 => write_int!(buf, value, i128),
ScalarType::ISize => write_int!(buf, value, isize),
#[cfg(feature = "net")]
ScalarType::IpAddr => write_int!(buf, value, core::net::IpAddr),
#[cfg(feature = "net")]
ScalarType::Ipv4Addr => write_int!(buf, value, core::net::Ipv4Addr),
#[cfg(feature = "net")]
ScalarType::Ipv6Addr => write_int!(buf, value, core::net::Ipv6Addr),
#[cfg(feature = "net")]
ScalarType::SocketAddr => write_int!(buf, value, core::net::SocketAddr),
_ => false,
};
if written {
return Some(buf.as_str().to_string());
}
}
if matches!(value.shape().def, Def::Scalar) && value.shape().vtable.has_display() {
let mut buf = ScalarBuffer::new();
let _ = write!(buf, "{}", value);
return Some(buf.as_str().to_string());
}
None
}
fn write_scalar(&mut self, value: Peek<'_, '_>) -> Result<bool, Self::Error> {
if let Def::Option(_) = &value.shape().def
&& let Ok(opt) = value.into_option()
{
return match opt.value() {
Some(inner) => self.write_scalar(inner),
None => Ok(false),
};
}
if let Some(scalar_type) = value.scalar_type() {
let mut buf = ScalarBuffer::new();
let written = match scalar_type {
ScalarType::Unit => {
buf.push_str("null");
true
}
ScalarType::Bool => {
if let Ok(b) = value.get::<bool>() {
buf.push_str(if *b { "true" } else { "false" });
true
} else {
false
}
}
ScalarType::Char => {
if let Ok(c) = value.get::<char>() {
buf.push(*c);
true
} else {
false
}
}
ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
if let Some(s) = value.as_str() {
self.text(s)?;
return Ok(true);
}
false
}
ScalarType::F32 => {
if let Ok(v) = value.get::<f32>() {
self.write_float(*v as f64, &mut buf);
true
} else {
false
}
}
ScalarType::F64 => {
if let Ok(v) = value.get::<f64>() {
self.write_float(*v, &mut buf);
true
} else {
false
}
}
ScalarType::U8 => write_int!(buf, value, u8),
ScalarType::U16 => write_int!(buf, value, u16),
ScalarType::U32 => write_int!(buf, value, u32),
ScalarType::U64 => write_int!(buf, value, u64),
ScalarType::U128 => write_int!(buf, value, u128),
ScalarType::USize => write_int!(buf, value, usize),
ScalarType::I8 => write_int!(buf, value, i8),
ScalarType::I16 => write_int!(buf, value, i16),
ScalarType::I32 => write_int!(buf, value, i32),
ScalarType::I64 => write_int!(buf, value, i64),
ScalarType::I128 => write_int!(buf, value, i128),
ScalarType::ISize => write_int!(buf, value, isize),
#[cfg(feature = "net")]
ScalarType::IpAddr => write_display!(buf, value, core::net::IpAddr),
#[cfg(feature = "net")]
ScalarType::Ipv4Addr => write_display!(buf, value, core::net::Ipv4Addr),
#[cfg(feature = "net")]
ScalarType::Ipv6Addr => write_display!(buf, value, core::net::Ipv6Addr),
#[cfg(feature = "net")]
ScalarType::SocketAddr => write_display!(buf, value, core::net::SocketAddr),
_ => false,
};
if written {
self.text(buf.as_str())?;
return Ok(true);
}
}
if matches!(value.shape().def, Def::Scalar) && value.shape().vtable.has_display() {
let mut buf = ScalarBuffer::new();
let _ = write!(buf, "{}", value);
self.text(buf.as_str())?;
return Ok(true);
}
Ok(false)
}
fn write_float(&self, value: f64, buf: &mut ScalarBuffer) {
let _ = write!(buf, "{}", value);
}
}
impl<T: DomSerializer> WriteScalar for T {}
macro_rules! write_int {
($buf:expr, $value:expr, $ty:ty) => {{
if let Ok(v) = $value.get::<$ty>() {
let _ = write!($buf, "{}", v);
true
} else {
false
}
}};
}
use write_int;
#[cfg(feature = "net")]
macro_rules! write_display {
($buf:expr, $value:expr, $ty:ty) => {{
if let Ok(v) = $value.get::<$ty>() {
let _ = write!($buf, "{}", v);
true
} else {
false
}
}};
}
#[cfg(feature = "net")]
use write_display;
pub struct ScalarBuffer {
inline: [u8; 32],
len: usize,
overflow: Option<String>,
}
impl ScalarBuffer {
pub fn new() -> Self {
Self {
inline: [0u8; 32],
len: 0,
overflow: None,
}
}
pub fn as_str(&self) -> &str {
if let Some(ref s) = self.overflow {
s.as_str()
} else {
unsafe { core::str::from_utf8_unchecked(&self.inline[..self.len]) }
}
}
fn push_str(&mut self, s: &str) {
if let Some(ref mut overflow) = self.overflow {
overflow.push_str(s);
} else if self.len + s.len() <= self.inline.len() {
self.inline[self.len..self.len + s.len()].copy_from_slice(s.as_bytes());
self.len += s.len();
} else {
let mut heap = String::with_capacity(self.len + s.len() + 32);
heap.push_str(unsafe { core::str::from_utf8_unchecked(&self.inline[..self.len]) });
heap.push_str(s);
self.overflow = Some(heap);
}
}
fn push(&mut self, c: char) {
let mut buf = [0u8; 4];
let s = c.encode_utf8(&mut buf);
self.push_str(s);
}
}
impl Default for ScalarBuffer {
fn default() -> Self {
Self::new()
}
}
impl FmtWrite for ScalarBuffer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.push_str(s);
Ok(())
}
}