Skip to content

Improve tvf! macro for negative numerical values - #88

Open
oschijns wants to merge 17 commits into
mainfrom
improve-tvf-macro
Open

oschijns wants to merge 17 commits into
mainfrom
improve-tvf-macro

Conversation

@oschijns

Copy link
Copy Markdown
Contributor

Allow defining the sign of a numerical value without wrapping into into extra parenthesis.
from

  let buffer = tvf!(SimpleStringTvf {
      10 => (-10),
      11 => (-10.25),
      12 => (-2) as Signed,
      13 => (+2.125) as Float,
  });

to

  let buffer = tvf!(SimpleStringTvf {
      10 => -10,
      11 => -10.25,
      12 => -2 as Signed,
      13 => +2.125 as Float,
  });

@oschijns oschijns self-assigned this Aug 31, 2026
@oschijns
oschijns requested a review from reneca August 31, 2026 16:43
@reneca

reneca commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Some edge cases are not working with this solution. I think you should reconsider the negative sign parsing. It should be apply on the expression.
For me these should work (not the case right now):

let amount: i64 = 7;

let buffer = tvf!(SimpleStringTvf {
    1 => -amount as Signed,
});

assert_eq!(Ok(-7), buffer.get_signed(1));

Also for String conversion:

let buffer = tvf!(SimpleStringTvf {
    1 => -7 as String,
});

assert_eq!(
    Ok("-7"),
    buffer.get_string(1).map(|value| value.to_string()).as_deref(),
);

And maybe an error could be trigger if we try to negate an unsigned value:

let buffer = tvf!(SimpleStringTvf {
    1 => -7 as Unsigned,
    2 => -7u64,
});

assert_ne!(Ok(7), buffer.get_unsigned(1));
assert_ne!(Ok(7), buffer.get_unsigned(2));

@reneca reneca left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You fix common things, but we still have an issue regarding expression.
For example: -(left - right) as Signed, with left = 10 and right = 3, stores 7 instead of -7. Can you also consider it please ?

Also what can we do about these ?

-7 as Unsigned // stores 7
-7u64          // stores 7
-7 as Byte     // stores 7

BTW you didn't sign your last commit.
And can you increase prose_macros version to 0.5.1 please.

Comment thread prosa_macros/src/tvf/value.rs Outdated
// Check if the first element is a sign (+ or -)
let is_negative = if let Some(TokenTree::Punct(punct)) = tokens.peek() {
let negative = punct.as_char() == '-';
tokens.next(); // move to next token

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User can also put !false and it'll be consider as false. It should consume the token only if it's -.

@oschijns

oschijns commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Also what can we do about these ?

-7 as Unsigned // stores 7
-7u64          // stores 7
-7 as Byte     // stores 7

They should throw an error. I'll look into it.

@oschijns
oschijns marked this pull request as draft September 2, 2026 16:24
@oschijns

oschijns commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

I think I've fixed some of the issues. But I am not satisfied with the implementation.
value.rs and literal.rs are kind of doing the same thing so there should be a way to group them.

@oschijns

oschijns commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

The refactoring is done.
The existing tests pass and unary operator can be easily tweaked.
Maybe we could add support for format! to trivially format a primitive type into a string and deduce that the resulting field is a string.

@oschijns

Copy link
Copy Markdown
Contributor Author

Test borrow and dereference operators with strings.
Test using constants and variables as field identifiers.

Implement format! so we can trivially write:

  let buffer = tvf!(SimpleStringTvf {
      1 => format!("{:0<12}", var),
  });

@oschijns
oschijns marked this pull request as ready for review October 1, 2026 13:23
@oschijns
oschijns force-pushed the improve-tvf-macro branch 2 times, most recently from 4c6bb90 to a90a852 Compare October 5, 2026 08:27
@reneca
reneca self-requested a review October 14, 2026 09:03
Comment thread prosa_macros/src/tvf/parser.rs Outdated
Comment thread prosa_macros/src/tvf/parser.rs Outdated
TvfType::Signed => (modifier, quote![ as i64 ]),
TvfType::Unsigned => (modifier, quote![ as u64 ]),
TvfType::Float => (modifier, quote![ as f64 ]),
_ => (modifier.filter_out_numeric(), TokenStream::new()),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-"abc" give "abc", but -"abc" as String give an error. You should return an error when modifier.is_numeric() and the type is not Byte/Signed/Unsigned/Float.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-format!(..) should not work. Can you reject the case ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fixed now

Comment thread prosa_macros/src/tvf/parser.rs Outdated
Comment thread prosa_macros/src/tvf/parser.rs Outdated

/// Given a literal deduce a String
/// We pass an extra modifier argument for primitives before being converted into string literals
pub(crate) fn parse_string(literal: &syn::Lit, modifier: Modifier) -> Result<String, syn::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is lot ongoing in this.
But there is many case to handle.
It's maybe dumb, but could this be enough: (#modifier #lit).to_string() ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope it doesn't work, I encounter edge-cases

assertion `left == right` failed
  left: Ok("string from bytes")
 right: Ok("b\"string from bytes\"")

Comment thread prosa_macros/src/tvf/parser.rs Outdated
Comment thread prosa_macros/src/tvf/parser.rs Outdated
Comment thread prosa_macros/src/tvf/parser.rs Outdated
Comment thread prosa_macros/src/tvf/expr.rs Outdated
Comment thread prosa_book/src/ch02-01-tvf.md Outdated
Olivier Schyns added 12 commits October 21, 2026 14:35
…extra parenthesis

Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
…arsing then generating tokens

Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Olivier Schyns added 4 commits October 21, 2026 17:11
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>
Signed-off-by: Olivier Schyns <olivier.schyns@worldline.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants