Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

derive(Format): add field attribute to map a field with a method prior to formatting it #502

Open
japaric opened this issue Jun 4, 2021 · 4 comments
Labels
difficulty: medium Somewhat difficult to solve priority: medium Medium priority for the Knurling team status: needs design This feature needs design work to move forward type: enhancement Enhancement or feature request

Comments

@japaric
Copy link
Member

japaric commented Jun 4, 2021

Use case

You want to derive Format an a struct that contains fields whose types don't implement the Format trait but can be easily mapped to a type that does.
Examples include structs with heapless::Vec (implements Format as of 0.7.0) and NonZero* (see #) fields

Strawman proposal

// == `write!(f, "S1 {{ list: {}, .. }}", self.list.as_slice(), /* .. */)`
#[derive(Format)]
struct S1 {
    #[format(method = "as_slice")]
    list: Vec<u8, N>,
    // .. other fields ..
}

// == `write!(f, "S2 {{ index: {}, .. }}", self.index.get(), /* .. */)`
#[derive(Format)]
struct S2 {
    #[format(method = "get")]
    index: NonZeroU8,
    // .. other fields ..
}

Alternatives

  • The alternative is not doing this. It's not strictly necessary: it's possible to write a manual Format implementation

Unresolves questions

  • Is there an alternative design that's more flexible and covers this and other use cases? For a similar feature see serde's remote attribute
@japaric japaric added type: enhancement Enhancement or feature request status: needs design This feature needs design work to move forward labels Jun 4, 2021
@jamesmunns
Copy link

Just adding that I ran into this today as well, using a bunch of AtomicU32s for profiling counters. I ended up making a mirror-structure out of regular u32s just to derive Format on it.

struct Profiler {
    spim_p0_ints: AtomicU32,
    spim_p1_ints: AtomicU32,
    spim_p2_ints: AtomicU32,
    spim_p3_ints: AtomicU32,
    usb_writes: AtomicU32,
    report_sers: AtomicU32,
    bbq_push_bytes: AtomicU32,
    bbq_pull_bytes: AtomicU32,
    idle_loop_iters: AtomicU32,
}

#[derive(Format)]
struct Report {
    spim_p0_ints: u32,
    spim_p1_ints: u32,
    spim_p2_ints: u32,
    spim_p3_ints: u32,
    usb_writes: u32,
    report_sers: u32,
    bbq_push_bytes: u32,
    bbq_pull_bytes: u32,
    idle_loop_iters: u32,
}

Having something like this would have been great!

@Urhengulas
Copy link
Member

What do you think about doing it similar to serde, which gives you the possibility to serialize a field using a function (https://serde.rs/field-attrs.html#serialize_with)?

The advantage I see is that the user can provide their own function for formatting and is not limited to exiting methods. If the user wants to use an existing method, they can still call it in the function.

@japaric
Copy link
Member Author

japaric commented Jun 7, 2021

(https://serde.rs/field-attrs.html#serialize_with)?

Something like this may be difficult to implement with defmt 0.2 because the closest thing we have to a serde "Serializer" is Formatter and that is consumed when you call write! on it. This sounds doable with the multi-write! proposed in #492 however

@Urhengulas
Copy link
Member

(https://serde.rs/field-attrs.html#serialize_with)?

Something like this may be difficult to implement with defmt 0.2 because the closest thing we have to a serde "Serializer" is Formatter and that is consumed when you call write! on it. This sounds doable with the multi-write! proposed in #492 however

I mainly wanted to point out that they let you specify functions and not methods.

We could probably omit the formatter from the signature and just have a bound of fn(&T) -> impl Format.
Then I can either pass Vec::as_slice (from your example above) or my_custom_fn.

@Urhengulas Urhengulas added difficulty: medium Somewhat difficult to solve priority: medium Medium priority for the Knurling team labels Jun 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: medium Somewhat difficult to solve priority: medium Medium priority for the Knurling team status: needs design This feature needs design work to move forward type: enhancement Enhancement or feature request
Projects
None yet
Development

No branches or pull requests

3 participants