use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
pub trait ExtractData {
type Input;
type LeafData;
fn extract_data(&self, input: Self::Input) -> Self::LeafData;
}
pub struct NoData<In> {
marker: PhantomData<In>,
}
impl<In> Default for NoData<In> {
fn default() -> Self {
NoData {
marker: PhantomData,
}
}
}
impl<In> Clone for NoData<In> {
fn clone(&self) -> Self {
NoData::default()
}
}
impl<In> Debug for NoData<In> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str("NoData")
}
}
impl<In> ExtractData for NoData<In> {
type Input = In;
type LeafData = ();
fn extract_data(&self, _: In) -> () {
()
}
}
pub struct Owned<T> {
marker: PhantomData<T>,
}
impl<T> Default for Owned<T> {
fn default() -> Self {
Owned {
marker: PhantomData,
}
}
}
impl<T> Clone for Owned<T> {
fn clone(&self) -> Self {
Owned::default()
}
}
impl<T> Debug for Owned<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str("Owned")
}
}
impl<T> ExtractData for Owned<T> {
type Input = T;
type LeafData = T;
fn extract_data(&self, input: T) -> T {
input
}
}
pub struct ExtractFn<In, F> {
extractor: F,
phantom: PhantomData<In>,
}
impl<In, F> Debug for ExtractFn<In, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str("ExtractFn")
}
}
impl<In, F, Out> ExtractFn<In, F>
where
F: Fn(In) -> Out,
{
pub fn with(extractor: F) -> Self {
ExtractFn {
extractor,
phantom: PhantomData,
}
}
}
impl<In, F, Out> ExtractData for ExtractFn<In, F>
where
F: Fn(In) -> Out,
{
type Input = In;
type LeafData = Out;
fn extract_data(&self, input: In) -> Out {
(self.extractor)(input)
}
}
impl<In, Out> ExtractData for fn(In) -> Out {
type Input = In;
type LeafData = Out;
fn extract_data(&self, input: In) -> Out {
self(input)
}
}
pub fn no_data<In>() -> NoData<In> {
NoData::default()
}
pub fn owned<In>() -> Owned<In> {
Owned::default()
}
pub fn extract_with<In, Out>(extractor: fn(In) -> Out) -> fn(In) -> Out {
extractor
}
#[cfg(test)]
mod tests {
use super::{extract_with, no_data, owned};
#[derive(Debug)]
struct NonCloneable;
#[test]
fn no_data_is_cloneable() {
let extractor = no_data::<NonCloneable>();
let _ = extractor.clone();
}
#[test]
fn owned_is_always_cloneable() {
let extractor = owned::<NonCloneable>();
let _ = extractor.clone();
}
#[test]
fn result_of_extract_with_is_cloneable() {
let _capture = NonCloneable;
let extractor = extract_with(|s: &'static [u8]| {
s.len()
});
let _ = extractor.clone();
}
}