use crate::protocol_caller::ProtocolCaller;
use crate::{FromValue, InstallWith, Named, RawStr, Value, VmError, VmErrorKind};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::fmt::Write as _;
use std::iter;
use std::num::NonZeroUsize;
use thiserror::Error;
#[derive(Debug, Clone, Copy, Error)]
#[error("bad type string")]
pub struct TypeFromStrError(());
#[derive(Debug, Clone, Copy, Error)]
#[error("bad alignment string")]
pub struct AlignmentFromStrError(());
#[derive(Debug, Clone)]
pub struct Format {
pub(crate) value: Value,
pub(crate) spec: FormatSpec,
}
impl Named for Format {
const NAME: RawStr = RawStr::from_str("Format");
}
impl InstallWith for Format {}
impl FromValue for Format {
fn from_value(value: Value) -> Result<Self, VmError> {
Ok(*value.into_format()?)
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[non_exhaustive]
pub struct FormatSpec {
pub(crate) flags: Flags,
pub(crate) fill: char,
pub(crate) align: Alignment,
pub(crate) width: Option<NonZeroUsize>,
pub(crate) precision: Option<NonZeroUsize>,
pub(crate) format_type: Type,
}
impl FormatSpec {
pub fn new(
flags: Flags,
fill: char,
align: Alignment,
width: Option<NonZeroUsize>,
precision: Option<NonZeroUsize>,
format_type: Type,
) -> Self {
Self {
flags,
fill,
align,
width,
precision,
format_type,
}
}
fn float_traits(&self, n: f64) -> (f64, Alignment, char, Option<char>) {
if self.flags.test(Flag::SignAwareZeroPad) {
if n.is_sign_negative() {
(-n, Alignment::Right, '0', Some('-'))
} else {
(n, Alignment::Right, '0', None)
}
} else if self.flags.test(Flag::SignPlus) && n.is_sign_positive() {
(n, self.align, self.fill, Some('+'))
} else {
(n, self.align, self.fill, None)
}
}
fn int_traits(&self, n: i64) -> (i64, Alignment, char, Option<char>) {
if self.flags.test(Flag::SignAwareZeroPad) {
if n < 0 {
(-n, Alignment::Right, '0', Some('-'))
} else {
(n, Alignment::Right, '0', None)
}
} else if self.flags.test(Flag::SignPlus) && n >= 0 {
(n, self.align, self.fill, Some('+'))
} else {
(n, self.align, self.fill, None)
}
}
fn format_number(&self, buf: &mut String, n: i64) {
let mut buffer = itoa::Buffer::new();
buf.push_str(buffer.format(n));
}
fn format_float(&self, buf: &mut String, n: f64) -> Result<(), VmErrorKind> {
if let Some(precision) = self.precision {
write!(buf, "{:.*}", precision.get(), n).map_err(|_| VmErrorKind::FormatError)?;
} else {
let mut buffer = ryu::Buffer::new();
buf.push_str(buffer.format(n));
}
Ok(())
}
fn format_fill(
&self,
out: &mut String,
buf: &String,
align: Alignment,
fill: char,
sign: Option<char>,
) {
if let Some(sign) = sign {
out.push(sign);
}
let mut w = self.width.map(|n| n.get()).unwrap_or_default();
if w == 0 {
out.push_str(&buf);
return;
}
w = w
.saturating_sub(buf.chars().count())
.saturating_sub(sign.map(|_| 1).unwrap_or_default());
if w == 0 {
out.push_str(&buf);
return;
}
let mut filler = iter::repeat(fill).take(w);
match align {
Alignment::Left => {
out.push_str(&buf);
out.extend(filler);
}
Alignment::Center => {
out.extend((&mut filler).take(w / 2));
out.push_str(&buf);
out.extend(filler);
}
Alignment::Right => {
out.extend(filler);
out.push_str(&buf);
}
}
}
fn format_display(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
) -> Result<(), VmError> {
match value {
Value::Char(c) => {
buf.push(*c);
self.format_fill(out, buf, self.align, self.fill, None);
}
Value::String(s) => {
buf.push_str(&*s.borrow_ref()?);
self.format_fill(out, buf, self.align, self.fill, None);
}
Value::StaticString(s) => {
buf.push_str(s.as_ref());
self.format_fill(out, buf, self.align, self.fill, None);
}
Value::Integer(n) => {
let (n, align, fill, sign) = self.int_traits(*n);
self.format_number(buf, n);
self.format_fill(out, buf, align, fill, sign);
}
Value::Float(n) => {
let (n, align, fill, sign) = self.float_traits(*n);
self.format_float(buf, n)?;
self.format_fill(out, buf, align, fill, sign);
}
_ => {
return Err(VmError::from(VmErrorKind::FormatError));
}
}
Ok(())
}
fn format_debug(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
caller: impl ProtocolCaller,
) -> Result<(), VmError> {
match value {
Value::String(s) => {
write!(out, "{:?}", &*s.borrow_ref()?).map_err(|_| VmErrorKind::FormatError)?;
}
Value::StaticString(s) => {
write!(out, "{:?}", s.as_ref()).map_err(|_| VmErrorKind::FormatError)?;
}
Value::Integer(n) => {
let (n, align, fill, sign) = self.int_traits(*n);
self.format_number(buf, n);
self.format_fill(out, buf, align, fill, sign);
}
Value::Float(n) => {
let (n, align, fill, sign) = self.float_traits(*n);
self.format_float(buf, n)?;
self.format_fill(out, buf, align, fill, sign);
}
value => {
let result = value.string_debug_with(out, caller)?;
result.map_err(|_| VmErrorKind::FormatError)?;
}
}
Ok(())
}
fn format_upper_hex(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
) -> Result<(), VmErrorKind> {
match value {
Value::Integer(n) => {
let (n, align, fill, sign) = self.int_traits(*n);
write!(buf, "{:X}", n).map_err(|_| VmErrorKind::FormatError)?;
self.format_fill(out, buf, align, fill, sign);
}
_ => {
return Err(VmErrorKind::FormatError);
}
}
Ok(())
}
fn format_lower_hex(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
) -> Result<(), VmErrorKind> {
match value {
Value::Integer(n) => {
let (n, align, fill, sign) = self.int_traits(*n);
write!(buf, "{:x}", n).map_err(|_| VmErrorKind::FormatError)?;
self.format_fill(out, buf, align, fill, sign);
}
_ => {
return Err(VmErrorKind::FormatError);
}
}
Ok(())
}
fn format_binary(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
) -> Result<(), VmErrorKind> {
match value {
Value::Integer(n) => {
let (n, align, fill, sign) = self.int_traits(*n);
write!(buf, "{:b}", n).map_err(|_| VmErrorKind::FormatError)?;
self.format_fill(out, buf, align, fill, sign);
}
_ => {
return Err(VmErrorKind::FormatError);
}
}
Ok(())
}
fn format_pointer(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
) -> Result<(), VmErrorKind> {
match value {
Value::Integer(n) => {
let (n, align, fill, sign) = self.int_traits(*n);
write!(buf, "{:p}", n as *const ()).map_err(|_| VmErrorKind::FormatError)?;
self.format_fill(out, buf, align, fill, sign);
}
_ => {
return Err(VmErrorKind::FormatError);
}
}
Ok(())
}
pub(crate) fn format(
&self,
value: &Value,
out: &mut String,
buf: &mut String,
caller: impl ProtocolCaller,
) -> Result<(), VmError> {
match self.format_type {
Type::Display => {
self.format_display(value, out, buf)?;
}
Type::Debug => {
self.format_debug(value, out, buf, caller)?;
}
Type::UpperHex => {
self.format_upper_hex(value, out, buf)?;
}
Type::LowerHex => {
self.format_lower_hex(value, out, buf)?;
}
Type::Binary => {
self.format_binary(value, out, buf)?;
}
Type::Pointer => {
self.format_pointer(value, out, buf)?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Type {
Display,
Debug,
UpperHex,
LowerHex,
Binary,
Pointer,
}
impl std::str::FromStr for Type {
type Err = TypeFromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"display" => Ok(Self::Display),
"debug" => Ok(Self::Debug),
"upper_hex" => Ok(Self::UpperHex),
"lower_hex" => Ok(Self::LowerHex),
"binary" => Ok(Self::Binary),
"pointer" => Ok(Self::Pointer),
_ => Err(TypeFromStrError(())),
}
}
}
impl Default for Type {
fn default() -> Self {
Self::Display
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Display => {
write!(f, "display")?;
}
Self::Debug => {
write!(f, "debug")?;
}
Self::UpperHex => {
write!(f, "upper_hex")?;
}
Self::LowerHex => {
write!(f, "lower_hex")?;
}
Self::Binary => {
write!(f, "binary")?;
}
Self::Pointer => {
write!(f, "pointer")?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Alignment {
Left,
Center,
Right,
}
impl Default for Alignment {
fn default() -> Self {
Self::Left
}
}
impl std::str::FromStr for Alignment {
type Err = AlignmentFromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"left" => Ok(Self::Left),
"center" => Ok(Self::Center),
"right" => Ok(Self::Right),
_ => Err(AlignmentFromStrError(())),
}
}
}
impl fmt::Display for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Left => {
write!(f, "left")?;
}
Self::Center => {
write!(f, "center")?;
}
Self::Right => {
write!(f, "right")?;
}
}
Ok(())
}
}
#[derive(Clone, Copy)]
#[repr(u32)]
#[non_exhaustive]
pub enum Flag {
SignPlus,
SignMinus,
Alternate,
SignAwareZeroPad,
}
#[derive(Clone, Copy, Default, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Flags(u32);
impl Flags {
pub fn is_empty(self) -> bool {
self.0 == 0
}
pub fn into_u32(self) -> u32 {
self.0
}
#[inline]
pub fn set(&mut self, flag: Flag) {
self.0 |= &(1 << flag as u32);
}
#[inline]
pub fn test(&self, flag: Flag) -> bool {
(self.0 & (1 << flag as u32)) != 0
}
}
impl From<u32> for Flags {
fn from(flags: u32) -> Self {
Self(flags)
}
}
impl fmt::Debug for Flags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
macro_rules! fmt_flag {
($flag:ident, $o:ident, $spec:literal) => {
if self.test(Flag::$flag) {
if !std::mem::take(&mut $o) {
write!(f, ", ")?;
}
write!(f, $spec)?;
}
};
}
let mut o = true;
write!(f, "Flags{{")?;
fmt_flag!(SignPlus, o, "+");
fmt_flag!(SignMinus, o, "-");
fmt_flag!(Alternate, o, "#");
fmt_flag!(SignAwareZeroPad, o, "0");
write!(f, "}}")?;
Ok(())
}
}