Dynamic collection

⚓ Rust    📅 2025-11-13    👤 surdeus    👁️ 4      

surdeus

Info

This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Dynamic collection

Is this an appropriate implementation of a dynamic collection? I'm aiming for a collection I can hold in some structs but where the struct is not generic over the collection. I had it previously implemented generically, but it really didn't make sense with e.g. this PowerSeries I have stubbed below.

I'm happy enough with a boxed iterator in the general Sequence trait and with boxing the trait itself in DynSequence. I would love if I could avoid the lifetimes especially in PowerSeries, but I can live with them. I just don't want them leaking too far.

use num::{One, Zero};

// Sequence

pub trait Sequence {

    /// Type for the terms of the `Sequence`
    type Term: Clone;

    /// Returns an iterator of Sequence terms
    fn terms(&self) -> Box<dyn Iterator<Item=Self::Term> + '_>;

    /// Is a finite sequence
    fn is_finite_sequence(&self) -> bool;

    // /// Truncates a Sequence and returns a Vec
    fn truncation(&self, len: usize) -> Vec<Self::Term>
    where Self: Clone {
        self.terms().take(len).collect::<Vec<_>>()
    }

}

// Sequence impls

impl<T> Sequence for Vec<T>
where T: Clone {
    type Term = T;
    fn terms(&self) -> Box<dyn Iterator<Item=T> + '_> {
        Box::new(self.iter().cloned())
    }
    fn is_finite_sequence(&self) -> bool {
        true
    }
}

impl<F, T> Sequence for F
where F: Fn(usize) -> T, T: Clone {
    type Term = T;
    fn terms(&self) -> Box<dyn Iterator<Item=T> + '_> {
        Box::new((0..).map(self))
    }
    fn is_finite_sequence(&self) -> bool {
        false
    }
}

// Dynamic Sequence

struct DynSequence<'a, T>(Box<dyn Sequence<Term=T> + 'a>) where T: Clone;

impl<'a, T> DynSequence<'a, T>
where T: Clone + 'a {
    pub fn new<S>(s: S) -> Self
    where S: Sequence<Term=T> + 'a {
        Self(Box::new(s))
    }
}

impl<'a, T> Sequence for DynSequence<'a, T>
where T: Clone {
    type Term = T;
    fn terms(&self) -> Box<dyn Iterator<Item=Self::Term> + '_> {
        self.0.terms()
    }
    fn is_finite_sequence(&self) -> bool {
        self.0.is_finite_sequence()
    }
}

// Client: PowerSeries

struct PowerSeries<'a, T>
where T: Clone + 'a {
    coefficients: DynSequence<'a, T>
}

impl<'a, T> PowerSeries<'a, T>
where T: Clone + 'a {

    /// Constructs a new `PowerSeries` with the given coefficients
    pub fn new<S>(coefficients: S) -> Self
    where S: Sequence<Term = T> + 'a {
        Self {
            coefficients: DynSequence::new(coefficients),
        }
    }

    pub fn is_finite(&self) -> bool {
        self.coefficients.is_finite_sequence()
    }

    /// Truncates the `PowerSeries` and returns a [`Polynomial`] with the given number of terms
    pub fn truncate(&self, num_terms: usize) -> PowerSeries<'_, T> {
        PowerSeries::new(self.coefficients.terms().take(num_terms).collect::<Vec<_>>())
    }

    fn eval(&self, x: T) -> Result<T, MyError>
    where T: Clone + Zero + One + std::ops::Mul<T, Output=T> {

        if (!self.coefficients.is_finite_sequence()) { return Err(MyError::InfiniteOperation) }

        let mut x_n = T::one();
        let mut sum = T::zero();
        for coefficient in self.coefficients.terms() {
            sum = sum + x_n.clone() * coefficient;
            x_n = x_n * x.clone();
        }

        Ok(sum)
    }

}


// Stubbed for the prototype

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum MyError {
    InfiniteOperation,
}
impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InfiniteOperation => write!(f, "Infinite operation"),
        }
    }
}
impl std::error::Error for MyError { }


// Usage

#[derive(Debug, Clone)]
struct Blah;
fn main() {
    let ps = PowerSeries::new(vec![Blah]);
    assert!(ps.is_finite());
    let ps = PowerSeries::new(vec![1; 5]);
    assert_eq!(ps.eval(2), Ok(1+2+4+8+16));
    assert_eq!(ps.truncate(3).eval(2), Ok(1+2+4));
}

3 posts - 2 participants

Read full topic

🏷️ Rust_feed