geoarrow_array/scalar/
multilinestring.rs

1use arrow_buffer::OffsetBuffer;
2use geo_traits::MultiLineStringTrait;
3use geoarrow_schema::Dimension;
4
5use crate::array::CoordBuffer;
6use crate::eq::multi_line_string_eq;
7use crate::scalar::LineString;
8use crate::util::OffsetBufferUtils;
9
10/// An Arrow equivalent of a MultiLineString
11///
12/// This implements [MultiLineStringTrait], which you can use to extract data.
13#[derive(Debug, Clone)]
14pub struct MultiLineString<'a> {
15    pub(crate) coords: &'a CoordBuffer,
16
17    /// Offsets into the ring array where each geometry starts
18    pub(crate) geom_offsets: &'a OffsetBuffer<i32>,
19
20    /// Offsets into the coordinate array where each ring starts
21    pub(crate) ring_offsets: &'a OffsetBuffer<i32>,
22
23    pub(crate) geom_index: usize,
24
25    start_offset: usize,
26}
27
28impl<'a> MultiLineString<'a> {
29    pub(crate) fn new(
30        coords: &'a CoordBuffer,
31        geom_offsets: &'a OffsetBuffer<i32>,
32        ring_offsets: &'a OffsetBuffer<i32>,
33        geom_index: usize,
34    ) -> Self {
35        let (start_offset, _) = geom_offsets.start_end(geom_index);
36        Self {
37            coords,
38            geom_offsets,
39            ring_offsets,
40            geom_index,
41            start_offset,
42        }
43    }
44
45    pub(crate) fn native_dim(&self) -> Dimension {
46        self.coords.dim()
47    }
48}
49
50impl<'a> MultiLineStringTrait for MultiLineString<'a> {
51    type InnerLineStringType<'b>
52        = LineString<'a>
53    where
54        Self: 'b;
55
56    fn num_line_strings(&self) -> usize {
57        let (start, end) = self.geom_offsets.start_end(self.geom_index);
58        end - start
59    }
60
61    unsafe fn line_string_unchecked(&self, i: usize) -> Self::InnerLineStringType<'_> {
62        LineString::new(self.coords, self.ring_offsets, self.start_offset + i)
63    }
64}
65
66impl<'a> MultiLineStringTrait for &'a MultiLineString<'a> {
67    type InnerLineStringType<'b>
68        = LineString<'a>
69    where
70        Self: 'b;
71
72    fn num_line_strings(&self) -> usize {
73        let (start, end) = self.geom_offsets.start_end(self.geom_index);
74        end - start
75    }
76
77    unsafe fn line_string_unchecked(&self, i: usize) -> Self::InnerLineStringType<'_> {
78        LineString::new(self.coords, self.ring_offsets, self.start_offset + i)
79    }
80}
81
82impl<G: MultiLineStringTrait<T = f64>> PartialEq<G> for MultiLineString<'_> {
83    fn eq(&self, other: &G) -> bool {
84        multi_line_string_eq(self, other)
85    }
86}
87
88#[cfg(test)]
89mod test {
90    use geoarrow_schema::{Dimension, MultiLineStringType};
91
92    use crate::builder::MultiLineStringBuilder;
93    use crate::test::multilinestring::{ml0, ml1};
94    use crate::trait_::GeoArrowArrayAccessor;
95
96    /// Test Eq where the current index is true but another index is false
97    #[test]
98    fn test_eq_other_index_false() {
99        let typ = MultiLineStringType::new(Dimension::XY, Default::default());
100
101        let arr1 = MultiLineStringBuilder::from_multi_line_strings(
102            vec![ml0(), ml1()].as_slice(),
103            typ.clone(),
104        )
105        .finish();
106        let arr2 =
107            MultiLineStringBuilder::from_multi_line_strings(vec![ml0(), ml0()].as_slice(), typ)
108                .finish();
109
110        assert_eq!(arr1.value(0).unwrap(), arr2.value(0).unwrap());
111        assert_ne!(arr1.value(1).unwrap(), arr2.value(1).unwrap());
112    }
113}