Skip to main content

owl_structural_model/
operands.rs

1//! Arity-checked source occurrences in one structural value.
2
3use crate::StructuralModelError;
4use serde::{Deserialize, Deserializer, Serialize};
5use std::ops::Deref;
6
7/// An ordered structural association with a minimum occurrence count.
8/// Construction needs no traits on the supplied payload type.
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
10#[serde(transparent)]
11pub struct OperandList<T, const MIN: usize> {
12    // bounded: operands of one caller-budgeted structural value, never a graph.
13    items: Vec<T>,
14}
15impl<T, const MIN: usize> OperandList<T, MIN> {
16    /// Check the minimum occurrence count without interpreting operands.
17    /// # Errors
18    /// Returns a structural error when fewer than `MIN` occurrences are supplied.
19    pub fn try_new(items: Vec<T>) -> Result<Self, StructuralModelError> {
20        if items.len() < MIN {
21            return Err(StructuralModelError::InvalidFormat {
22                kind: "structural operands",
23                value: items.len().to_string(),
24                message: match MIN {
25                    1 => "requires at least one operand",
26                    2 => "requires at least two operands",
27                    _ => "too few operands for the structural minimum",
28                },
29            });
30        }
31        Ok(Self { items })
32    }
33    /// Return source occurrences in their supplied order.
34    #[must_use]
35    pub fn as_slice(&self) -> &[T] {
36        &self.items
37    }
38    /// Consume this structural association.
39    #[must_use]
40    pub fn into_vec(self) -> Vec<T> {
41        self.items
42    }
43}
44impl<T> OperandList<T, 0> {
45    /// Construct an unrestricted, possibly empty association.
46    #[must_use]
47    pub fn new(items: Vec<T>) -> Self {
48        Self { items }
49    }
50}
51impl<T, const MIN: usize> Deref for OperandList<T, MIN> {
52    type Target = [T];
53    fn deref(&self) -> &Self::Target {
54        self.as_slice()
55    }
56}
57impl<'a, T, const MIN: usize> IntoIterator for &'a OperandList<T, MIN> {
58    type Item = &'a T;
59    type IntoIter = std::slice::Iter<'a, T>;
60    fn into_iter(self) -> Self::IntoIter {
61        self.items.iter()
62    }
63}
64impl<'de, T: Deserialize<'de>, const MIN: usize> Deserialize<'de> for OperandList<T, MIN> {
65    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
66        Self::try_new(Vec::<T>::deserialize(deserializer)?).map_err(serde::de::Error::custom)
67    }
68}