I'm trying to build a library to query Spatialite for geometric features. Initially I've queried the database for individual feature types with methods like points_of_interest
, paths
, etc. But I'd like to transition to something more generic. Yesterday I iterated through all spatial tables, then composed a union database query that retrieves all geospatial features in an area regardless of what table they're in. My code looks a bit like:
use std::any::Any;
use std::boxed::Box;
trait Feature {}
struct Point;
impl Feature for Point {}
struct Line;
impl Feature for Line{}
struct Features(Vec<Box<Feature>>);
impl Features {
fn new(features: Vec<Box<Feature>>) -> Self {
Features(features)
}
fn all(&self) -> &Vec<Box<Feature>> { &self.0 }
}
fn main() {
let point = Point;
let line = Line;
let collection: Vec<Box<Feature>> = vec![
Box::new(line),
Box::new(point)
];
let features = Features::new(collection);
}
Next I want to extract specific kinds of features. So an API might run something like:
let points: Vec<Box<Point>> = features.extract<Point>();
But nothing I do gets this working. Here's my current attempt:
/*fn extract<T>(&self) -> Vec<Box<T>> where T: Feature {
self.0.into_iter().filter(|v: &Any| v.is::<Box<T>>()).collect::<Vec<Feature>>()
}*/
When uncommented, I get:
error[E0599]: no method named `collect` found for type `std::iter::Filter<std::vec::IntoIter<std::boxed::Box<Feature>>, [closure@src/main.rs:24:35: 24:61]>` in the current scope
--> src/main.rs:24:63
|
24 | self.0.into_iter().filter(|v: &Any| v.is::<Box<T>>()).collect::<Vec<Feature>>()
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`std::iter::Filter<std::vec::IntoIter<std::boxed::Box<Feature>>, [closure@src/main.rs:24:35: 24:61]> : std::iter::Iterator`
`&mut std::iter::Filter<std::vec::IntoIter<std::boxed::Box<Feature>>, [closure@src/main.rs:24:35: 24:61]> : std::iter::Iterator`
error[E0631]: type mismatch in closure arguments
--> src/main.rs:24:28
|
24 | self.0.into_iter().filter(|v: &Any| v.is::<Box<T>>()).collect::<Vec<Feature>>()
| ^^^^^^ -------------------------- found signature of `for<'r> fn(&'r std::any::Any + 'static) -> _`
| |
| expected signature of `for<'r> fn(&'r std::boxed::Box<Feature>) -> _`
error: aborting due to 2 previous errors
error: Could not compile `interfaces`.
To learn more, run the command again with --verbose.
I've tried a number of things to get that working, but nothing seems to. Pointers appreciated. I'm also not super attached to that particular function signature, I just want a way to filter my vec of features to extract specific ones, then get back a correctly typed Vec.
As an aside, I can't wait for the compiler to stop inviting me to learn more quite so much, I know learning never ends,but man...