I have a set of Nom parsers for various Markup languages. Each takes &str
as input (c.f. parse-hyperlinks):
My goal is:
-
to tag the input string with the markup language used, e.g. "md" or "rst", by associating a type
-
statically dispatch two code versions for each parser:
a) the right type for this parser: the parser does its computation.
b) the wrong type: the parser returns
Err
. -
a generic parser combinator, that takes for example md-input
and skips all non-md parsers. -
to have a marker type, let say "all" for which the combinator
does not skip any parser.
I did explore what can be done with the PhantomData
type, but I think I am on the wrong track. Any better ideas?
use core::convert::AsRef;
use std::marker::PhantomData;
use std::println;
use std::str;
/// Hidden type tagging Markdown texts.
struct Md;
/// Hidden type tagging reStructuredText texts.
struct Rst;
#[derive(Debug)]
pub enum ParseError {
WrongMarkup,
}
// A phantom tuple struct which is generic over `A` with hidden parameter `B`.
#[derive(Debug, PartialEq)] // Allow equality test for this type.
struct Input<'a, A: 'a + AsRef<str> + ?Sized, B>(&'a A, PhantomData<B>);
fn some_md_computation<'a, I>(i: Input<'a, I, Md>) -> Result<&'a str, ParseError>
where
I: 'a + AsRef<str> + ?Sized,
{
let i = i.0.as_ref();
// Some computation.
Ok(&i[0..4])
}
// This does not work because:
// src/main.rs:17:6: B: !Md, negative bounds are not supported
// src/main.rs:27:1 fn rend the name `render_md` is defined multiple times
/*
fn some_md_computation<'a, I, B>(_i: Input<'a, I, B>) -> Result<&'a str, ParseError>
where
I: 'a + AsRef<str> + ?Sized,
B: !Md,
{
// Return Error.
Err(ParseError::WrongMarkup)
}
*/
fn main() {
let md_input: Input<str, Md> = Input("Markdown abc", PhantomData);
let md_output = some_md_computation(md_input).unwrap();
println!("{:?}", md_output); // Prints: ("Mark")
let _rst_input: Input<str, Rst> = Input("Markdown abc", PhantomData);
// I would like to be able to do this:
//let _ = some_md_computation(_rst_input).unwrap_err();
// But as the above does not work...
// src/main.rs:48:32 some_md_computation(... expected struct `Md`, found struct `Rst`
}