You're better off relying on polymorphism instead of trait "constructor"s based on lifetime parameters. For example, instead of Source<'a>, just make it Source. Then make Source::column polymorphic based on the lifetime associated with &self.
For example, the below compiles just fine:
mod data {
use std::collections::HashMap;
pub(crate) trait F64Column {
fn iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_>;
}
pub(crate) trait Column {
fn f64(&self) -> Option<&(dyn F64Column + '_)>;
}
pub(crate) trait Source {
fn column(&self, name: &str) -> Option<&(dyn Column + '_)>;
}
#[derive(Debug, Clone)]
pub(crate) enum VecColumn {
F64(Vec<f64>),
}
pub(crate) struct VecSource {
columns: HashMap<String, Box<dyn Column + 'static>>,
}
impl VecSource {
pub(crate) fn new() -> Self {
Self {
columns: HashMap::new(),
}
}
pub(crate) fn with_f64_column(mut self, name: &str, col: Vec<f64>) -> Self {
drop(
self.columns
.insert(name.to_owned(), Box::new(VecColumn::F64(col))),
);
self
}
}
impl F64Column for Vec<f64> {
fn iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
Box::new(
self.as_slice()
.iter()
.copied()
.map(|f| f.is_finite().then_some(f)),
)
}
}
impl Column for VecColumn {
fn f64(&self) -> Option<&(dyn F64Column + '_)> {
match *self {
Self::F64(ref v) => Some(v),
}
}
}
impl Source for VecSource {
fn column(&self, name: &str) -> Option<&(dyn Column + '_)> {
self.columns.get(name).map(|c| &**c)
}
}
}
mod ir {
use crate::data::VecColumn;
pub(crate) enum DataCol {
Inline(VecColumn),
SrcRef(String),
}
pub(crate) struct Figure {
pub x_data: DataCol,
pub y_data: DataCol,
}
}
mod drawing {
use crate::data::{Column, Source};
use crate::ir::{DataCol, Figure};
fn get_column<'a, D: Source>(col: &'a DataCol, data_source: &'a D) -> &'a dyn Column {
match *col {
DataCol::Inline(ref c) => c,
DataCol::SrcRef(ref name) => data_source.column(name).expect("Column not found"),
}
}
pub(crate) fn draw_figure<D: Source>(figure: &Figure, data_source: &D) {
let x_data = get_column(&figure.x_data, data_source);
let y_data = get_column(&figure.y_data, data_source);
let x_col = x_data.f64().expect("x_data is not f64");
let y_col = y_data.f64().expect("y_data is not f64");
println!("Drawing figure");
for (x, y) in x_col.iter().zip(y_col.iter()) {
println!(" ({}, {})", x.unwrap(), y.unwrap());
}
}
}
use data::{VecColumn, VecSource};
use ir::{DataCol, Figure};
fn main() {
let x: Vec<f64> = (0u8..10).map(f64::from).collect();
let y: Vec<f64> = x.iter().map(|a| a * a).collect();
let source = VecSource::new().with_f64_column("x", x);
let figure = Figure {
x_data: DataCol::SrcRef("x".to_owned()),
y_data: DataCol::Inline(VecColumn::F64(y)),
};
drawing::draw_figure(&figure, &source);
}