-
Notifications
You must be signed in to change notification settings - Fork 3
log: mw_log_fmt implementation
#13
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
base: main
Are you sure you want to change the base?
Conversation
- Replacement for `core::fmt`. - Unit tests.
License Check Results🚀 The license check job ran with the Bazel command: bazel run //:license-checkStatus: Click to expand output |
|
The created documentation from the pull request is available at: docu-html |
| #[macro_export] | ||
| macro_rules! score_write { | ||
| ($dst:expr, $($arg:tt)*) => { | ||
| write($dst, mw_log_format_args!($($arg)*)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be qualified with the expansion of the crate name:
| write($dst, mw_log_format_args!($($arg)*)) | |
| $crate::write($dst, mw_log_format_args!($($arg)*)) |
| $crate::score_write!($dst, "\n") | ||
| }; | ||
| ($dst:expr, $($arg:tt)*) => { | ||
| write($dst, mw_log_format_args_nl!($($arg)*)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
| new_format!(new_debug, ScoreDebug); | ||
| new_format!(new_display, ScoreDisplay); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you planning to call the new_format! macro in more places beyond these two? Declaring a macro just to create two copies of a relatively short method seems like overkill, and makes the code harder to understand (especially because it kills IDE support within the method implementation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ye also there will be rule functions over macros. So we shall change that wherever possible.
|
|
||
| macro_rules! new_format { | ||
| ($name:ident, $trait:ident) => { | ||
| pub const fn $name<T: $trait>(value: &T, spec: FormatSpec) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fails to capture the lifetime of &T under 'a, which lets other code mutate value while Placeholder conceptionally contains a reference to value. Example:
let mut value = 5_u32;
let ph = Fragment::Placeholder(Placeholder::new_display(&value, FormatSpec::new()));
value = 6; // This must be prevented!
mw_log_fmt::write(&mut buffer, Arguments(&[ph])).unwrap(); // This will write "6"Constrain &T to fix this:
| pub const fn $name<T: $trait>(value: &T, spec: FormatSpec) -> Self { | |
| pub const fn $name<T: $trait>(value: &'a T, spec: FormatSpec) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have more insight why this works like that ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The compiler accepts the old version, because the body of the function erases the lifetime of the reference value: &'b T by converting it to a pointer. The closure within the function then effectively converts this pointer to a reference &'a T, which is wrong, but the compiler doesn't know that.
When doing reference-pointer-reference roundtrips, you must be very careful with lifetime annotations in function signatures and on type declarations, because the compiler won't complain if you make a mistake.
| pub trait ScoreWrite { | ||
| fn write_bool(&mut self, v: &bool, spec: &FormatSpec) -> Result; | ||
| fn write_f32(&mut self, v: &f32, spec: &FormatSpec) -> Result; | ||
| fn write_f64(&mut self, v: &f64, spec: &FormatSpec) -> Result; | ||
| fn write_i8(&mut self, v: &i8, spec: &FormatSpec) -> Result; | ||
| fn write_i16(&mut self, v: &i16, spec: &FormatSpec) -> Result; | ||
| fn write_i32(&mut self, v: &i32, spec: &FormatSpec) -> Result; | ||
| fn write_i64(&mut self, v: &i64, spec: &FormatSpec) -> Result; | ||
| fn write_u8(&mut self, v: &u8, spec: &FormatSpec) -> Result; | ||
| fn write_u16(&mut self, v: &u16, spec: &FormatSpec) -> Result; | ||
| fn write_u32(&mut self, v: &u32, spec: &FormatSpec) -> Result; | ||
| fn write_u64(&mut self, v: &u64, spec: &FormatSpec) -> Result; | ||
| fn write_str(&mut self, v: &str, spec: &FormatSpec) -> Result; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This architecture requires that every implementer of ScoreWrite needs to handle every supported type. That's a lot of duplication.
Why do it like this, instead of taking the approach in core::fmt::Write? That trait only requires implementing write_str, and it provides a predefined write_fmt convenience method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a requirement from S-CORE. Basically, the Log backend is using type information to pack it with some specific formats, ie DLT. So there is no othe way like live this to back which can decide what to do with it.
| @@ -1,24 +0,0 @@ | |||
| # ******************************************************************************* | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no src structs inside component modules. (use custom lib.rs path in cargo toml.)
| // | ||
|
|
||
| use crate::FormatSpec; | ||
| use core::fmt::Error as CoreFmtError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this ? this is not vcertified as of now.
| } | ||
| } | ||
|
|
||
| pub trait ScoreWrite { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docs.
| fn write_str(&mut self, v: &str, spec: &FormatSpec) -> Result; | ||
| } | ||
|
|
||
| #[derive(Debug)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shall not use core::fmt in our fmt ;)
| &self.spec | ||
| } | ||
|
|
||
| pub fn fmt(&self, f: &mut dyn ScoreWrite, spec: &FormatSpec) -> Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hide &mut dyn ScoreWrite this after some wrapping type with deref for now if needed
| $fmt::fmt(&v, &mut w, &FormatSpec::new()).unwrap(); | ||
| assert_eq!(w.get(), format!("{v}")); | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think you could use a generic fn instead macro or ?
| new_format!(new_debug, ScoreDebug); | ||
| new_format!(new_display, ScoreDisplay); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ye also there will be rule functions over macros. So we shall change that wherever possible.
|
|
||
| macro_rules! new_format { | ||
| ($name:ident, $trait:ident) => { | ||
| pub const fn $name<T: $trait>(value: &T, spec: FormatSpec) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have more insight why this works like that ?
| pub trait ScoreWrite { | ||
| fn write_bool(&mut self, v: &bool, spec: &FormatSpec) -> Result; | ||
| fn write_f32(&mut self, v: &f32, spec: &FormatSpec) -> Result; | ||
| fn write_f64(&mut self, v: &f64, spec: &FormatSpec) -> Result; | ||
| fn write_i8(&mut self, v: &i8, spec: &FormatSpec) -> Result; | ||
| fn write_i16(&mut self, v: &i16, spec: &FormatSpec) -> Result; | ||
| fn write_i32(&mut self, v: &i32, spec: &FormatSpec) -> Result; | ||
| fn write_i64(&mut self, v: &i64, spec: &FormatSpec) -> Result; | ||
| fn write_u8(&mut self, v: &u8, spec: &FormatSpec) -> Result; | ||
| fn write_u16(&mut self, v: &u16, spec: &FormatSpec) -> Result; | ||
| fn write_u32(&mut self, v: &u32, spec: &FormatSpec) -> Result; | ||
| fn write_u64(&mut self, v: &u64, spec: &FormatSpec) -> Result; | ||
| fn write_str(&mut self, v: &str, spec: &FormatSpec) -> Result; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a requirement from S-CORE. Basically, the Log backend is using type information to pack it with some specific formats, ie DLT. So there is no othe way like live this to back which can decide what to do with it.
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this shall be also ScoreDebug or ?
core::fmt.Notes for Reviewer
Pre-Review Checklist for the PR Author
Checklist for the PR Reviewer
Post-review Checklist for the PR Author
References
Closes #