#![doc(hidden)]
use std::mem::{size_of, zeroed};
use std::fmt::*;
pub trait FormatTrait {
#[inline]
fn allowed<T>() -> bool;
#[inline]
fn perform<T>(t: &T, f: &mut Formatter) -> Result;
}
trait Specialized<T> {
#[inline]
fn allowed() -> bool;
#[inline]
fn perform(t: &T, f: &mut Formatter) -> Result;
}
macro_rules! impl_format_trait {
($($name:ident,)*) => {
$(
impl<T> Specialized<T> for dyn $name {
#[inline]
default fn allowed() -> bool { false }
#[inline]
default fn perform(_: &T, _: &mut Formatter) -> Result {
panic!()
}
}
impl<T: $name> Specialized<T> for dyn $name {
#[inline]
fn allowed() -> bool { true }
#[inline]
fn perform(t: &T, f: &mut Formatter) -> Result {
t.fmt(f)
}
}
impl FormatTrait for dyn $name {
#[inline]
fn allowed<T>() -> bool { <Self as Specialized<T>>::allowed() }
#[inline]
fn perform<T>(t: &T, f: &mut Formatter) -> Result {
<Self as Specialized<T>>::perform(t, f)
}
}
)*
}
}
impl_format_trait! {
Display, Debug, LowerExp, UpperExp, Octal, Pointer, Binary, LowerHex,
UpperHex,
}
#[inline]
fn get_formatter<T, F: FormatTrait + ?Sized>()
-> Option<impl Fn(&T, &mut Formatter) -> Result>
{
if F::allowed::<T>() {
Some(F::perform::<T>)
} else {
None
}
}
#[inline]
fn combined<A, B, LHS, RHS>(a: &A, f: &mut Formatter) -> Result
where LHS: Fn(&A) -> &B, RHS: Fn(&B, &mut Formatter) -> Result
{
let lhs = unsafe { zeroed::<LHS>() };
let rhs = unsafe { zeroed::<RHS>() };
rhs(lhs(a), f)
}
type FormatFn<T> = fn(&T, &mut Formatter) -> Result;
#[inline]
fn make_combined<A, B, LHS, RHS>(_: LHS, _: RHS) -> FormatFn<A>
where LHS: Fn(&A) -> &B, RHS: Fn(&B, &mut Formatter) -> Result
{
assert!(size_of::<LHS>() == 0,
"Mapper from parent to child must be zero-sized, instead size was {}",
size_of::<LHS>());
assert!(size_of::<RHS>() == 0,
"Formatting function must be zero-sized, instead size was {}",
size_of::<RHS>());
combined::<A, B, LHS, RHS>
}
#[inline]
pub fn combine<F, A, B, Func>(func: Func)
-> Option<FormatFn<A>>
where F: FormatTrait + ?Sized, Func: Fn(&A) -> &B
{
get_formatter::<B, F>().map(|r| make_combined(func, r))
}
trait SpecUsize {
#[inline]
fn convert<T>(f: fn(&T) -> &Self) -> Option<fn(&T) -> &usize>;
}
impl<U> SpecUsize for U {
#[inline]
default fn convert<T>(_: fn(&T) -> &Self) -> Option<fn(&T) -> &usize> { None }
}
impl SpecUsize for usize {
#[inline]
fn convert<T>(f: fn(&T) -> &usize) -> Option<fn(&T) -> &usize> { Some(f) }
}
#[inline]
pub fn as_usize<A, B>(f: fn(&A) -> &B) -> Option<fn(&A) -> &usize> {
<B as SpecUsize>::convert::<A>(f)
}
pub trait FormatArgs {
fn validate_name(name: &str) -> Option<usize>;
fn validate_index(index: usize) -> bool;
fn get_child<F: FormatTrait + ?Sized>(index: usize) -> Option<FormatFn<Self>>;
fn as_usize(index: usize) -> Option<fn(&Self) -> &usize>;
}