I'm writing a small program which convert a few file formats, following a uniform configuration.
Configuration has simple expression to perform logical and/or of match & capture values using regex (or matching date or whatever).
- I want to define
trait Matcher
wrappingregex::Regex
, as some input have non-regex matching logic. - I want to let
trait Matcher
have a methodcheck
which gets their input and returns a reference containing with the same lifetime as the input (e.g. substring ofinput
).
Now I have an issue related to GATs, I cannot implement my requirements without using generic_associated_types.
As the tool is my personal tool, I can be tolerate with building with nightly for a short period, but if I need to wait to see generic_associated_types comes to stable, I should try to find another way to achieve this...
How can I do the following codes without GATs?
#![feature(generic_associated_types)]
use std::convert::From;
trait Matcher: for<'a> From<&'a str> {
type Input<'a>: Copy;
fn check<'a>(&self, input: Self::Input<'a>) -> Option<&'a str>;
}
struct FooMatcher {}
#[derive(Clone, Copy)]
struct FooInput<'a>(&'a str);
impl<'a> From<&'a str> for FooMatcher {
fn from(_: &'a str) -> FooMatcher {
FooMatcher {}
}
}
impl Matcher for FooMatcher {
type Input<'a> = FooInput<'a>;
fn check<'a>(&self, input: Self::Input<'a>) -> Option<&'a str> {
if input.0 == "foo" {
Some(&input.0)
} else {
None
}
}
}
#[derive(Clone, Copy)]
struct BarInput<'a>(&'a str);
struct BarMatcher {
pattern: String,
}
impl<'m> From<&'m str> for BarMatcher {
fn from(pattern: &'m str) -> Self {
BarMatcher {
pattern: pattern.to_string(),
}
}
}
impl Matcher for BarMatcher {
type Input<'a> = BarInput<'a>;
fn check<'a>(&self, input: Self::Input<'a>) -> Option<&'a str> {
if input.0.contains(self.pattern.as_str()) {
Some(&input.0)
} else {
None
}
}
}
struct OrMatcher<M: Matcher>(Vec<M>);
impl<'m, M, T> From<T> for OrMatcher<M>
where
M: Matcher,
T: AsRef<[&'m str]>,
{
fn from(config: T) -> OrMatcher<M> {
let mut ret = Vec::new();
for cfg in config.as_ref() {
ret.push((*cfg).into());
}
OrMatcher(ret)
}
}
impl<M: Matcher> OrMatcher<M> {
fn check<'a>(&self, input: M::Input<'a>) -> Option<&'a str> {
self.0.iter().find_map(|m| m.check(input))
}
}
fn main() {
let m1 = FooMatcher {};
println!("{:?}", m1.check(FooInput("foo")));
println!("{:?}", m1.check(FooInput("bar")));
let m2 = BarMatcher {
pattern: "specified".to_string(),
};
println!("{:?}", m2.check(BarInput("foo")));
println!("{:?}", m2.check(BarInput("==specified==")));
let m3: OrMatcher<FooMatcher> = (&["cond1", "cond2"]).into();
println!("{:?}", m3.check(FooInput("foo")));
println!("{:?}", m3.check(FooInput("bar")));
let m4: OrMatcher<BarMatcher> = (&["bar", "baz"]).into();
println!("{:?}", m4.check(BarInput("foo")));
println!("{:?}", m4.check(BarInput("bar")));
println!("{:?}", m4.check(BarInput("baz")));
}
Output:
Some("foo")
None
None
Some("==specified==")
Some("foo")
None
None
Some("bar")
Some("baz")
Errors:
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 2.56s
Running `target/debug/playground`