use crate::std::fmt;
use super::internal::{Internal, InternalVisitor};
use super::{Error, ValueBag};
impl<'v> ValueBag<'v> {
pub const fn from_fill<T>(value: &'v T) -> Self
where
T: Fill,
{
ValueBag {
inner: Internal::Fill(value),
}
}
}
pub trait Fill {
fn fill(&self, slot: Slot) -> Result<(), Error>;
}
impl<F> Fill for F
where
F: Fn(Slot) -> Result<(), Error>,
{
fn fill(&self, slot: Slot) -> Result<(), Error> {
(self)(slot)
}
}
pub struct Slot<'s, 'f> {
visitor: &'s mut dyn InternalVisitor<'f>,
}
impl<'s, 'f> fmt::Debug for Slot<'s, 'f> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Slot").finish()
}
}
impl<'s, 'f> Slot<'s, 'f> {
pub(crate) fn new(visitor: &'s mut dyn InternalVisitor<'f>) -> Self {
Slot { visitor }
}
pub(crate) fn fill<F>(self, f: F) -> Result<(), Error>
where
F: FnOnce(&mut dyn InternalVisitor<'f>) -> Result<(), Error>,
{
f(self.visitor)
}
pub fn fill_any<T>(self, value: T) -> Result<(), Error>
where
T: Into<ValueBag<'f>>,
{
self.fill(|visitor| value.into().inner.internal_visit(visitor))
}
}
#[cfg(test)]
mod tests {
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
use super::*;
use crate::std::string::ToString;
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn fill_value_borrowed() {
struct TestFill;
impl Fill for TestFill {
fn fill(&self, slot: Slot) -> Result<(), Error> {
let dbg = &1 as &dyn fmt::Debug;
slot.fill_debug(dbg)
}
}
assert_eq!("1", ValueBag::from_fill(&TestFill).to_string());
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn fill_cast() {
struct TestFill;
impl Fill for TestFill {
fn fill(&self, slot: Slot) -> Result<(), Error> {
slot.fill_any("a string")
}
}
assert_eq!(
"a string",
ValueBag::from_fill(&TestFill)
.to_borrowed_str()
.expect("invalid value")
);
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn fill_fn_cast() {
assert_eq!(
42u64,
ValueBag::from_fill(&|slot: Slot| slot.fill_any(42u64))
.to_u64()
.unwrap()
);
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn fill_fn_borrowed() {
#[derive(Debug)]
struct MyValue;
let value = MyValue;
assert_eq!(
format!("{:?}", value),
format!(
"{:?}",
ValueBag::from_fill(&|slot: Slot| slot.fill_debug(&value))
)
);
}
}