I'm struggling to see the point in this. Your roll example using Winnow. Not really that much (un)wrapping logic:
use winnow::{Result, ascii::digit1, combinator::separated_pair, prelude::*};
#[derive(Debug, PartialEq)]
struct Roll {
count: u32,
sides: u32,
}
fn number(input: &mut &str) -> Result<u32> {
digit1.try_map(str::parse).parse_next(input)
}
fn roll(input: &mut &str) -> Result<Roll> {
let (count, sides) = separated_pair(number, 'd', number).parse_next(input)?;
Ok(Roll { count, sides })
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_roll() {
let input = &mut "3d6";
assert_eq!(roll(input), Ok(Roll { count: 3, sides: 6 }));
}
}