Skip to main content

geonative_core/
feature.rs

1//! A `Feature` is one row: an optional feature ID, an optional geometry, and
2//! an indexed attribute vector that parallels [`crate::Schema::fields`].
3
4use crate::{geometry::Geometry, value::Value};
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct Feature {
8    /// Feature identifier. `None` for formats that don't expose stable FIDs.
9    pub fid: Option<i64>,
10    /// Geometry payload. `None` for attribute-only tables (GDB system tables,
11    /// DBF-only Shapefile sidecars).
12    pub geometry: Option<Geometry>,
13    /// Attribute values, in the same order as `Schema::fields`. Length
14    /// **must** equal `Schema::fields.len()`.
15    pub attributes: Vec<Value>,
16}
17
18impl Feature {
19    pub fn new(fid: Option<i64>, geometry: Option<Geometry>, attributes: Vec<Value>) -> Self {
20        Self {
21            fid,
22            geometry,
23            attributes,
24        }
25    }
26
27    pub fn attribute(&self, idx: usize) -> Option<&Value> {
28        self.attributes.get(idx)
29    }
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35    use crate::{Coord, Geometry};
36
37    #[test]
38    fn construct_and_access() {
39        let f = Feature::new(
40            Some(42),
41            Some(Geometry::Point(Coord::xy(1.0, 2.0))),
42            vec![Value::Int32(7), Value::String("hi".into())],
43        );
44        assert_eq!(f.fid, Some(42));
45        assert!(matches!(f.geometry, Some(Geometry::Point(_))));
46        assert_eq!(f.attribute(0), Some(&Value::Int32(7)));
47        assert_eq!(f.attribute(2), None);
48    }
49}