yewstack / implicit-clone

Immutable types and ImplicitClone trait similar to Copy
19 stars 10 forks source link

Attempt to improve the documentation #45

Closed cecton closed 12 months ago

cecton commented 12 months ago

I think this example is now more reflecting the actual usage. What do you think?

// In the host library source code:

use implicit_clone::ImplicitClone;
use implicit_clone::unsync::{IArray, IString};

macro_rules! html_input {
    (<input $(type={$ty:expr})? $(name={$name:expr})? $(value={$value:expr})?>) => {{
        let mut input = Input::new();
        $(input.type = $ty.into();)*
        $(input.name.replace($name.into());)*
        $(input.value.replace($value.into());)*
        input
    }}
}

#[derive(Clone)]
pub struct Input {
    ty: IString,
    name: Option<IString>,
    value: Option<IString>,
}

impl ImplicitClone for Input {}

impl Input {
    pub fn new() -> Self {
        Self {
            ty: IString::Static("text"),
            name: None,
            value: None,
        }
    }
}

impl std::fmt::Display for Input {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "<input type=\"{}\"", self.ty)?;
        if let Some(name) = self.name.as_ref() {
            write!(f, " name=\"{}\"", name)?;
        }
        if let Some(value) = self.value.as_ref() {
            write!(f, " value=\"{}\"", value)?;
        }
        write!(f, ">")
    }
}

// In the user's source code:

fn component(age: &IString) -> IArray<Input> {
    // `age` is implicitly cloned to the 2 different inputs
    let input1 = html_input!(<input name={"age"} value={age}>);
    let input2 = html_input!(<input name={"age"} value={age}>);

    IArray::from(vec![input1, input2])
}

let age = IString::from(20.to_string());
let output = component(&age);
let output_str = output
    .iter()
    .map(|x| x.to_string())
    .collect::<Vec<_>>()
    .join("");

assert_eq!(
    output_str,
    r#"<input type="text" name="age" value="20"><input type="text" name="age" value="20">"#,
);
kirillsemyonkin commented 12 months ago

Yes the main point would be that the clone happens implicitly (here using .into()?), so that user would have easier time typing out similar lines without having to think about the moves/lifetimes.

If that example-test passes, and does what I just mentioned above, then any such example will be very good.

IArray::from(vec![input1, input2])

Tiny nitpick/question, should IArray::from([input1, input2]) be used instead? (is it possible?)

cecton commented 12 months ago

Tiny nitpick/question, should IArray::from([input1, input2]) be used instead? (is it possible?)

I asked myself the same question but not it doesn't work. But it's actually very logical. IArray has only 3 variants:

cecton commented 12 months ago

Yes the main point would be that the clone happens implicitly (here using .into()?),

Yes exactly, the into is the magic here. I think I will put back the setter functions to make it more obvious.

cecton commented 12 months ago

Ok I think now it's perfect but I don't want you to feel forced on my idea.

kirillsemyonkin commented 12 months ago
  • the tests lose their "doc as example" aspect

They can't. Even if you make them a bit less reader-friendly, it does not change the fact that tests document code.

  • the comments with the "not compile" things are now being actually tested

It was like my first time writing tests in OSS space actually. So if you were able to improve this, I'm just simply glad that my incompetence was solved at some point.

I don't want you to feel forced on my idea

I mean, ideally both code tests and doc would be aiding users at everything, but I do think having it easily visible in the doc is a good idea. Everyone trying to change the code and having a discussion is good, we're all trying to work in the best interests of the project, each other and the users after all.