otter/types/terms/
tuple.rs1use core::marker::PhantomData;
6use std::ffi::{c_int, c_uint};
7
8use crate::types::sealed::Sealed;
9use crate::types::{AnyTerm, Env, Invariant, RawTerm, Term};
10
11#[derive(Clone, Copy)]
20pub struct Tuple<'id> {
21 raw_term: RawTerm,
22 _id: Invariant<'id>,
23}
24
25impl<'id> Tuple<'id> {
26 #[crate::raw]
27 pub(crate) fn from_raw(raw_term: RawTerm) -> Self {
28 Self { raw_term, _id: PhantomData }
29 }
30
31 pub fn with_elements(self, env: impl Env<'id>) -> TupleView<'id> {
37 let mut arity: c_int = 0;
38 let mut array: *const RawTerm = std::ptr::null();
39 let ok = unsafe { enif_ffi::get_tuple(env.raw_env(), self.raw_term, &mut arity, &mut array) };
40 assert!(ok != 0, "enif_get_tuple failed on a validated Tuple");
41 let raw_elements = if arity == 0 {
44 &[][..]
45 } else {
46 unsafe { std::slice::from_raw_parts(array, arity as usize) }
47 };
48 TupleView { raw_term: self.raw_term, raw_elements, _id: PhantomData }
49 }
50
51 pub fn from_terms<I, T>(env: impl Env<'id>, terms: I) -> Tuple<'id>
54 where
55 I: IntoIterator<Item = T>,
56 T: Term<'id>,
57 {
58 let raw: Vec<RawTerm> = terms.into_iter().map(|t| t.raw_term()).collect();
59 let raw_term = unsafe {
60 enif_ffi::make_tuple_from_array(env.raw_env(), raw.as_ptr(), raw.len() as c_uint)
61 };
62 Tuple { raw_term, _id: PhantomData }
63 }
64
65 pub fn is_tuple(env: impl Env<'id>, term: impl Term<'id>) -> bool {
67 unsafe { enif_ffi::is_tuple(env.raw_env(), term.raw_term()) != 0 }
68 }
69}
70
71impl PartialEq for Tuple<'_> {
72 fn eq(&self, other: &Self) -> bool {
73 unsafe { enif_ffi::is_identical(self.raw_term, other.raw_term) != 0 }
74 }
75}
76
77impl Eq for Tuple<'_> {}
78
79impl PartialOrd for Tuple<'_> {
80 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
81 Some(self.cmp(other))
82 }
83}
84
85impl Ord for Tuple<'_> {
86 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
87 let c = unsafe { enif_ffi::compare(self.raw_term, other.raw_term) };
88 c.cmp(&0)
89 }
90}
91
92impl std::fmt::Debug for Tuple<'_> {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 write!(f, "Tuple")
95 }
96}
97
98impl<'id> Sealed for Tuple<'id> {}
99
100impl<'id> Term<'id> for Tuple<'id> {
101 fn raw_term(self) -> RawTerm {
102 self.raw_term
103 }
104}
105
106#[derive(Clone, Copy)]
123pub struct TupleView<'id> {
124 raw_term: RawTerm,
125 raw_elements: &'id [RawTerm],
126 _id: Invariant<'id>,
127}
128
129impl<'id> TupleView<'id> {
130 fn elements(self) -> &'id [AnyTerm<'id>] {
134 unsafe { std::mem::transmute::<&'id [RawTerm], &'id [AnyTerm<'id>]>(self.raw_elements) }
138 }
139
140 pub fn len(self) -> usize {
142 self.raw_elements.len()
143 }
144
145 pub fn is_empty(self) -> bool {
147 self.raw_elements.is_empty()
148 }
149}
150
151impl<'id> std::ops::Index<usize> for TupleView<'id> {
152 type Output = AnyTerm<'id>;
153
154 fn index(&self, i: usize) -> &AnyTerm<'id> {
156 &self.elements()[i]
157 }
158}
159
160impl<'id> IntoIterator for TupleView<'id> {
161 type Item = AnyTerm<'id>;
162 type IntoIter = std::iter::Copied<std::slice::Iter<'id, AnyTerm<'id>>>;
163
164 fn into_iter(self) -> Self::IntoIter {
165 self.elements().iter().copied()
166 }
167}
168
169impl std::fmt::Debug for TupleView<'_> {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 write!(f, "TupleView")
172 }
173}
174
175impl<'id> Sealed for TupleView<'id> {}
176
177impl<'id> Term<'id> for TupleView<'id> {
178 fn raw_term(self) -> RawTerm {
179 self.raw_term
180 }
181}