Dynamic collection
⚓ Rust 📅 2025-11-13 👤 surdeus 👁️ 4Is 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
🏷️ Rust_feed