Skip to main content

iqdb_types/
vector.rs

1//! Dense `f32` vectors: an owned [`Vector`] and a borrowed [`VectorRef`].
2//!
3//! These are the raw embeddings the iqdb spine indexes and searches. They are
4//! thin, immutable wrappers — construct one from its data through the
5//! fallible [`Vector::new`] (or the equivalent [`TryFrom<Vec<f32>>`] impl),
6//! read it back through the accessors, and (for [`Vector`]) reclaim the
7//! buffer with [`Vector::into_inner`]. There is no in-place mutation.
8
9use crate::error::{IqdbError, Result};
10
11/// An owned dense vector of `f32` components.
12///
13/// Construct one with the fallible [`Vector::new`] (which rejects empty
14/// inputs and non-finite components) or its [`TryFrom<Vec<f32>>`] sibling;
15/// read its components with [`as_slice`](Vector::as_slice) or reclaim the
16/// buffer with [`into_inner`](Vector::into_inner).
17///
18/// Validation at this boundary keeps the rest of the spine free of input
19/// checks: once a `Vector` exists, the math never has to defend against
20/// empty, NaN, or infinite components.
21///
22/// # Representation
23///
24/// Components are stored in a `Box<[f32]>`, not a `Vec<f32>`: a `Vector` is
25/// immutable after construction, so it never needs spare capacity. This makes
26/// the value one machine word smaller than a `Vec`-backed wrapper and
27/// guarantees the backing allocation is sized exactly to the data — meaningful
28/// when millions of vectors are held resident.
29///
30/// # Examples
31///
32/// ```
33/// use iqdb_types::{IqdbError, Vector};
34///
35/// let v = Vector::new(vec![1.0, 0.0, 0.0]).unwrap();
36/// assert_eq!(v.dim(), 3);
37/// assert_eq!(v.as_slice(), &[1.0, 0.0, 0.0]);
38///
39/// // Empty and non-finite inputs are rejected at construction.
40/// assert_eq!(Vector::new(Vec::new()).unwrap_err(), IqdbError::InvalidVector);
41/// assert_eq!(
42///     Vector::new(vec![1.0, f32::NAN]).unwrap_err(),
43///     IqdbError::InvalidVector,
44/// );
45/// ```
46#[derive(Debug, Clone, PartialEq)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct Vector(Box<[f32]>);
49
50impl Vector {
51    /// Builds a `Vector` from `data`, validating the contents.
52    ///
53    /// Returns [`IqdbError::InvalidVector`] when:
54    ///
55    /// - `data` is empty, or
56    /// - any component is not finite (NaN or ±infinity).
57    ///
58    /// Validating at the type boundary keeps the rest of the spine — and
59    /// every consumer crate — free of input checks. Once a `Vector` is in
60    /// hand the math can trust its contents.
61    ///
62    /// The `data` buffer is shrunk to fit (`into_boxed_slice`) on success, so
63    /// the stored allocation carries no spare capacity.
64    ///
65    /// # Examples
66    ///
67    /// ```
68    /// use iqdb_types::{IqdbError, Vector};
69    ///
70    /// let v = Vector::new(vec![0.1, 0.2, 0.3]).unwrap();
71    /// assert_eq!(v.dim(), 3);
72    ///
73    /// assert_eq!(
74    ///     Vector::new(Vec::new()).unwrap_err(),
75    ///     IqdbError::InvalidVector,
76    /// );
77    /// assert_eq!(
78    ///     Vector::new(vec![1.0, f32::INFINITY]).unwrap_err(),
79    ///     IqdbError::InvalidVector,
80    /// );
81    /// ```
82    #[inline]
83    pub fn new(data: Vec<f32>) -> Result<Self> {
84        if data.is_empty() {
85            return Err(IqdbError::InvalidVector);
86        }
87        if data.iter().any(|v| !v.is_finite()) {
88            return Err(IqdbError::InvalidVector);
89        }
90        Ok(Self(data.into_boxed_slice()))
91    }
92
93    /// Builds a `Vector` from `data` without validating it.
94    ///
95    /// Available only when the crate is built with the `testing` feature.
96    /// Production code MUST use [`Vector::new`] (or `TryFrom`); a production
97    /// build of `iqdb-types` cannot compile a call to this constructor.
98    ///
99    /// Reserved for tests that deliberately need to construct otherwise-
100    /// invalid vectors to assert downstream behavior on bad input.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// # #[cfg(feature = "testing")]
106    /// # {
107    /// use iqdb_types::Vector;
108    ///
109    /// // Constructible only under the `testing` feature.
110    /// let v = Vector::new_unchecked(vec![f32::NAN]);
111    /// assert_eq!(v.len(), 1);
112    /// # }
113    /// ```
114    #[cfg(any(test, feature = "testing"))]
115    #[inline]
116    #[must_use]
117    pub fn new_unchecked(data: Vec<f32>) -> Self {
118        Self(data.into_boxed_slice())
119    }
120
121    /// Borrows the components as a slice.
122    ///
123    /// # Examples
124    ///
125    /// ```
126    /// use iqdb_types::Vector;
127    ///
128    /// let v = Vector::new(vec![0.5, 0.5]).unwrap();
129    /// assert_eq!(v.as_slice(), &[0.5, 0.5]);
130    /// ```
131    #[inline]
132    #[must_use]
133    pub fn as_slice(&self) -> &[f32] {
134        &self.0
135    }
136
137    /// Returns the number of components.
138    ///
139    /// # Examples
140    ///
141    /// ```
142    /// use iqdb_types::Vector;
143    ///
144    /// assert_eq!(Vector::new(vec![1.0, 2.0]).unwrap().len(), 2);
145    /// ```
146    #[inline]
147    #[must_use]
148    pub fn len(&self) -> usize {
149        self.0.len()
150    }
151
152    /// Returns `true` if the vector has no components.
153    ///
154    /// A `Vector` produced by [`Vector::new`] is never empty (empty inputs
155    /// are rejected at construction); this method is `false` for every
156    /// `Vector` outside the `testing`-gated `Vector::new_unchecked`.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// use iqdb_types::Vector;
162    ///
163    /// assert!(!Vector::new(vec![1.0]).unwrap().is_empty());
164    /// ```
165    #[inline]
166    #[must_use]
167    pub fn is_empty(&self) -> bool {
168        self.0.is_empty()
169    }
170
171    /// Returns the dimensionality of the vector (its component count).
172    ///
173    /// # Examples
174    ///
175    /// ```
176    /// use iqdb_types::Vector;
177    ///
178    /// assert_eq!(Vector::new(vec![1.0, 2.0, 3.0]).unwrap().dim(), 3);
179    /// ```
180    #[inline]
181    #[must_use]
182    pub fn dim(&self) -> usize {
183        self.0.len()
184    }
185
186    /// Consumes the vector and returns the underlying buffer as a `Vec<f32>`.
187    ///
188    /// This is allocation-free: the boxed slice is converted back to a `Vec`
189    /// with capacity equal to its length (`Box<[f32]>::into_vec`), no copy.
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// use iqdb_types::Vector;
195    ///
196    /// let v = Vector::new(vec![1.0, 2.0]).unwrap();
197    /// assert_eq!(v.into_inner(), vec![1.0, 2.0]);
198    /// ```
199    #[inline]
200    #[must_use]
201    pub fn into_inner(self) -> Vec<f32> {
202        self.0.into_vec()
203    }
204}
205
206impl TryFrom<Vec<f32>> for Vector {
207    type Error = IqdbError;
208
209    /// Delegates to [`Vector::new`]: rejects empty and non-finite inputs
210    /// with [`IqdbError::InvalidVector`].
211    ///
212    /// # Examples
213    ///
214    /// ```
215    /// use iqdb_types::Vector;
216    ///
217    /// let v: Vector = vec![1.0, 0.0].try_into().unwrap();
218    /// assert_eq!(v.dim(), 2);
219    /// ```
220    #[inline]
221    fn try_from(data: Vec<f32>) -> Result<Self> {
222        Self::new(data)
223    }
224}
225
226/// A borrowed dense vector of `f32` components.
227///
228/// A zero-copy view over a `&[f32]`, for passing query vectors without taking
229/// ownership. It is [`Copy`]. With the `serde` feature it derives
230/// [`Serialize`](https://docs.rs/serde) only — a borrowed view cannot be
231/// deserialized into, since there is nowhere to own the decoded data.
232///
233/// # Examples
234///
235/// ```
236/// use iqdb_types::VectorRef;
237///
238/// let data = [1.0, 0.0, 0.0];
239/// let v = VectorRef::from(&data[..]);
240/// assert_eq!(v.dim(), 3);
241/// assert_eq!(v.as_slice(), &[1.0, 0.0, 0.0]);
242/// ```
243#[derive(Debug, Clone, Copy, PartialEq)]
244#[cfg_attr(feature = "serde", derive(serde::Serialize))]
245pub struct VectorRef<'a>(&'a [f32]);
246
247impl<'a> VectorRef<'a> {
248    /// Borrows the components as a slice.
249    ///
250    /// # Examples
251    ///
252    /// ```
253    /// use iqdb_types::VectorRef;
254    ///
255    /// let data = [0.5, 0.5];
256    /// assert_eq!(VectorRef::from(&data[..]).as_slice(), &[0.5, 0.5]);
257    /// ```
258    #[inline]
259    #[must_use]
260    pub fn as_slice(&self) -> &[f32] {
261        self.0
262    }
263
264    /// Returns the number of components.
265    ///
266    /// # Examples
267    ///
268    /// ```
269    /// use iqdb_types::VectorRef;
270    ///
271    /// let data = [1.0, 2.0];
272    /// assert_eq!(VectorRef::from(&data[..]).len(), 2);
273    /// ```
274    #[inline]
275    #[must_use]
276    pub fn len(&self) -> usize {
277        self.0.len()
278    }
279
280    /// Returns `true` if the view has no components.
281    ///
282    /// # Examples
283    ///
284    /// ```
285    /// use iqdb_types::VectorRef;
286    ///
287    /// let empty: [f32; 0] = [];
288    /// assert!(VectorRef::from(&empty[..]).is_empty());
289    /// ```
290    #[inline]
291    #[must_use]
292    pub fn is_empty(&self) -> bool {
293        self.0.is_empty()
294    }
295
296    /// Returns the dimensionality of the view (its component count).
297    ///
298    /// # Examples
299    ///
300    /// ```
301    /// use iqdb_types::VectorRef;
302    ///
303    /// let data = [1.0, 2.0, 3.0];
304    /// assert_eq!(VectorRef::from(&data[..]).dim(), 3);
305    /// ```
306    #[inline]
307    #[must_use]
308    pub fn dim(&self) -> usize {
309        self.0.len()
310    }
311
312    /// Returns the borrowed slice with its original lifetime.
313    ///
314    /// # Examples
315    ///
316    /// ```
317    /// use iqdb_types::VectorRef;
318    ///
319    /// let data = [1.0, 2.0];
320    /// let v = VectorRef::from(&data[..]);
321    /// let slice: &[f32] = v.into_inner();
322    /// assert_eq!(slice, &[1.0, 2.0]);
323    /// ```
324    #[inline]
325    #[must_use]
326    pub fn into_inner(self) -> &'a [f32] {
327        self.0
328    }
329}
330
331impl<'a> From<&'a [f32]> for VectorRef<'a> {
332    #[inline]
333    fn from(data: &'a [f32]) -> Self {
334        Self(data)
335    }
336}