1use std::collections::BTreeMap;
2use std::fmt::Write;
3
4use try_hash::TryHash;
5
6#[derive(Debug, Clone)]
7pub struct Tuple<T> {
8 unnamed: Vec<T>,
9 named: BTreeMap<String, T>,
10 named_order: Vec<String>,
11}
12
13impl<T: PartialEq> PartialEq for Tuple<T> {
14 fn eq(&self, other: &Self) -> bool {
15 self.unnamed == other.unnamed && self.named == other.named
16 }
17}
18
19impl<T: Eq> Eq for Tuple<T> {}
20
21impl<T: PartialOrd> PartialOrd for Tuple<T> {
22 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
23 match self.unnamed.partial_cmp(&other.unnamed) {
24 Some(core::cmp::Ordering::Equal) => {}
25 ord => return ord,
26 }
27 self.named.partial_cmp(&other.named)
28 }
29}
30
31impl<T: Ord> Ord for Tuple<T> {
32 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
33 match self.unnamed.cmp(&other.unnamed) {
34 core::cmp::Ordering::Equal => {}
35 ord => return ord,
36 }
37 self.named.cmp(&other.named)
38 }
39}
40
41impl<T: std::hash::Hash> std::hash::Hash for Tuple<T> {
42 fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
43 for unnamed in &self.unnamed {
44 unnamed.hash(hasher);
45 }
46 for (name, value) in &self.named {
47 std::hash::Hash::hash(name, hasher);
48 value.hash(hasher);
49 }
50 }
51}
52
53impl<T: TryHash> TryHash for Tuple<T> {
54 type Error = T::Error;
55 fn try_hash(&self, hasher: &mut impl std::hash::Hasher) -> Result<(), Self::Error> {
56 for unnamed in &self.unnamed {
57 unnamed.try_hash(hasher)?;
58 }
59 for (name, value) in &self.named {
60 std::hash::Hash::hash(name, hasher);
61 value.try_hash(hasher)?;
62 }
63 Ok(())
64 }
65}
66
67impl<T> Tuple<T> {
68 pub fn empty() -> Self {
69 Self {
70 unnamed: vec![],
71 named: BTreeMap::new(),
72 named_order: vec![],
73 }
74 }
75 pub fn single_named(name: impl Into<String>, value: T) -> Self {
76 let mut result = Self::empty();
77 result.add_named(name, value);
78 result
79 }
80 pub fn is_empty(&self) -> bool {
81 self.unnamed.is_empty() && self.named.is_empty()
82 }
83 pub fn get_unnamed(&self) -> &[T] {
84 &self.unnamed
85 }
86 pub fn get_named(&self, name: &str) -> Option<&T> {
87 self.named.get(name)
88 }
89 pub fn take_named(&mut self, name: &str) -> Option<T> {
90 let value = self.named.remove(name);
91 if value.is_some() {
92 self.named_order.retain(|s| s != name);
93 }
94 value
95 }
96 pub fn add_unnamed(&mut self, value: T) {
97 self.unnamed.push(value);
98 }
99 pub fn add_named(&mut self, name: impl Into<String>, value: T) {
100 let name: String = name.into();
101 if self.named.insert(name.clone(), value).is_none() {
102 self.named_order.push(name.clone());
103 }
104 }
105 pub fn add(&mut self, name: Option<String>, value: T) {
106 match name {
107 Some(name) => self.add_named(name, value),
108 None => self.add_unnamed(value),
109 }
110 }
111 pub fn fmt_with_name<'a>(&'a self, name: &'a str) -> NamedTupleFmt<'a, T> {
112 NamedTupleFmt { name, tuple: self }
113 }
114 pub fn unnamed(&self) -> impl Iterator<Item = &T> + '_ {
115 self.unnamed.iter()
116 }
117 pub fn named(&self) -> impl Iterator<Item = (&str, &T)> + '_ {
118 self.named_order
119 .iter()
120 .map(|key| (key.as_str(), &self.named[key]))
121 }
122 pub fn into_field_values(mut self) -> impl Iterator<Item = T> {
123 self.unnamed.into_iter().chain(
124 self.named_order
125 .into_iter()
126 .map(move |name| self.named.remove(&name).unwrap()),
127 )
128 }
129 pub fn show_fields(&self) -> impl std::fmt::Display + '_ {
130 struct ShowFields<'a, T>(&'a Tuple<T>);
131 impl<T> std::fmt::Display for ShowFields<'_, T> {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 let mut first = true;
134 if !self.0.unnamed.is_empty() {
135 write!(f, "{} unnamed fields", self.0.unnamed.len())?;
136 first = false;
137 }
138 for name in &self.0.named_order {
139 if first {
140 first = false;
141 } else {
142 write!(f, ", ")?;
143 }
144 write!(f, "{name:?}")?;
145 }
146 Ok(())
147 }
148 }
149 ShowFields(self)
150 }
151 pub fn as_ref(&self) -> Tuple<&T> {
152 Tuple {
153 unnamed: self.unnamed.iter().collect(),
154 named: self
155 .named
156 .iter()
157 .map(|(key, value)| (key.clone(), value))
158 .collect(),
159 named_order: self.named_order.clone(),
160 }
161 }
162 pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Tuple<U> {
163 Tuple {
164 unnamed: self.unnamed.into_iter().map(&mut f).collect(),
165 named: self
166 .named
167 .into_iter()
168 .map(|(key, value)| (key, f(value)))
169 .collect(),
170 named_order: self.named_order,
171 }
172 }
173 pub fn values(&self) -> impl Iterator<Item = &T> + '_ {
174 self.unnamed
175 .iter()
176 .chain(self.named_order.iter().map(|name| &self.named[name]))
177 }
178}
179
180pub struct TupleIntoIter<T> {
181 unnamed: <Vec<T> as IntoIterator>::IntoIter,
182 names: <Vec<String> as IntoIterator>::IntoIter,
183 named: BTreeMap<String, T>,
184}
185
186impl<T> Iterator for TupleIntoIter<T> {
187 type Item = (Option<String>, T);
188 fn next(&mut self) -> Option<Self::Item> {
189 if let Some(value) = self.unnamed.next() {
190 return Some((None, value));
191 }
192 let name = self.names.next()?;
193 let value = self.named.remove(&name).unwrap();
194 Some((Some(name), value))
195 }
196}
197
198impl<T> IntoIterator for Tuple<T> {
199 type Item = (Option<String>, T);
200 type IntoIter = TupleIntoIter<T>;
201 fn into_iter(self) -> Self::IntoIter {
202 TupleIntoIter {
203 unnamed: self.unnamed.into_iter(),
204 names: self.named_order.into_iter(),
205 named: self.named,
206 }
207 }
208}
209
210#[derive(Debug, thiserror::Error)]
211pub enum IntoFixedErrorReason {
212 IncorrectAmountOfUnnamedFields { expected: usize, actual: usize },
213 NamedFieldNotPresent(String),
214 NamedFieldUnexpected(String),
215}
216
217impl std::fmt::Display for IntoFixedErrorReason {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 match self {
220 Self::NamedFieldNotPresent(name) => {
221 write!(f, "field {name:?} is not present")
222 }
223 Self::NamedFieldUnexpected(name) => {
224 write!(f, "field {name:?} was not expected")
225 }
226 Self::IncorrectAmountOfUnnamedFields { expected, actual } => {
227 write!(f, "expected {expected} unnamed fields, got {actual}")
228 }
229 }
230 }
231}
232
233#[derive(Debug, thiserror::Error)]
234pub struct IntoFixedError {
235 erased_value: Tuple<()>,
236 expected_unnamed_fields: usize,
237 expected_named_fields: Vec<String>,
238 optional_fields: Vec<String>,
239 #[source]
240 reason: IntoFixedErrorReason,
241}
242
243impl std::fmt::Display for IntoFixedError {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 write!(f, "expected ")?;
246 let mut started = false;
247 let mut start = |f: &mut std::fmt::Formatter| {
248 if started {
249 write!(f, ", ")
250 } else {
251 started = true;
252 Ok(())
253 }
254 };
255 if self.expected_unnamed_fields != 0 {
256 start(f)?;
257 write!(f, "{} unnamed fields", self.expected_unnamed_fields)?;
258 }
259 for name in &self.expected_named_fields {
260 start(f)?;
261 write!(f, "{name:?}")?;
262 }
263 if !self.optional_fields.is_empty() {
264 start(f)?;
265 write!(f, "optional ")?;
266 for (i, name) in self.optional_fields.iter().enumerate() {
267 if i != 0 {
268 write!(f, ", ")?;
269 }
270 write!(f, "{name:?}")?;
271 }
272 }
273 write!(f, " but got {}", self.erased_value.show_fields())
274 }
275}
276
277pub struct FixedTuple<const UNNAMED: usize, const NAMED: usize, const OPTIONAL: usize, T> {
278 unnamed: [T; UNNAMED],
279 named: [T; NAMED],
280 optional: [Option<T>; OPTIONAL],
281}
282
283impl<T> Tuple<T> {
284 pub fn into_fixed<const UNNAMED: usize, const NAMED: usize, const OPTIONAL: usize>(
285 mut self,
286 named: [&str; NAMED],
287 optional: [&str; OPTIONAL],
288 ) -> Result<FixedTuple<UNNAMED, NAMED, OPTIONAL, T>, IntoFixedError> {
289 let erased_value = self.as_ref().map(|_| ());
290 macro_rules! error {
291 ($reason:expr) => {
292 Err(IntoFixedError {
293 expected_unnamed_fields: UNNAMED,
294 expected_named_fields: named.iter().map(|s| s.to_string()).collect(),
295 optional_fields: optional.iter().map(|s| s.to_string()).collect(),
296 reason: $reason,
297 erased_value,
298 })
299 };
300 }
301
302 if self.unnamed.len() != UNNAMED {
303 return error!(IntoFixedErrorReason::IncorrectAmountOfUnnamedFields {
304 expected: UNNAMED,
305 actual: self.unnamed.len()
306 });
307 }
308 let unnamed: [T; UNNAMED] = self.unnamed.try_into().ok().unwrap();
309
310 if let Some(name) = self
311 .named_order
312 .iter()
313 .find(|name| !named.contains(&name.as_str()) && !optional.contains(&name.as_str()))
314 {
315 return error!(IntoFixedErrorReason::NamedFieldUnexpected(name.to_string()));
316 }
317
318 if let Some(name) = named.iter().find(|&&name| !self.named.contains_key(name)) {
319 return error!(IntoFixedErrorReason::NamedFieldNotPresent(name.to_string()));
320 }
321
322 let named = named.map(|name| self.named.remove(name).unwrap());
323 let optional = optional.map(|name| self.named.remove(name));
324
325 Ok(FixedTuple {
326 unnamed,
327 named,
328 optional,
329 })
330 }
331 pub fn into_unnamed<const N: usize>(self) -> Result<[T; N], IntoFixedError> {
333 Ok(self.into_fixed([], [])?.unnamed)
334 }
335 pub fn into_named_opt<const N: usize, const OPT: usize>(
336 self,
337 names: [&str; N],
338 optional: [&str; OPT],
339 ) -> Result<([T; N], [Option<T>; OPT]), IntoFixedError> {
340 let FixedTuple {
341 unnamed: [],
342 named,
343 optional,
344 } = self.into_fixed(names, optional)?;
345 Ok((named, optional))
346 }
347 pub fn into_named<const N: usize>(self, names: [&str; N]) -> Result<[T; N], IntoFixedError> {
348 Ok(self.into_fixed::<0, N, 0>(names, [])?.named)
349 }
350 pub fn into_single_named(self, name: &str) -> Result<T, IntoFixedError> {
351 self.into_named([name]).map(|[value]| value)
352 }
353}
354
355#[derive(Debug, thiserror::Error)]
356pub enum TupleZipError {
357 #[error("different amount of unnamed fields: {0} vs {1}")]
358 DifferentUnnamedAmount(usize, usize),
359 #[error("field {0} not present in other")]
360 NamedNotPresentInOther(String),
361 #[error("field {0} is only present in other")]
362 NamedOnlyPresentInOther(String),
363}
364
365impl<T> Tuple<T> {
366 pub fn zip<U>(mut self, mut other: Tuple<U>) -> Result<Tuple<(T, U)>, TupleZipError> {
367 if self.unnamed.len() != other.unnamed.len() {
368 return Err(TupleZipError::DifferentUnnamedAmount(
369 self.unnamed.len(),
370 other.unnamed.len(),
371 ));
372 }
373 for name in self.named.keys() {
374 if !other.named.contains_key(name) {
375 return Err(TupleZipError::NamedNotPresentInOther(name.to_owned()));
376 }
377 }
378 for name in other.named.keys() {
379 if !self.named.contains_key(name) {
380 return Err(TupleZipError::NamedOnlyPresentInOther(name.to_owned()));
381 }
382 }
383 Ok(Tuple {
384 unnamed: self.unnamed.into_iter().zip(other.unnamed).collect(),
385 named: self
386 .named_order
387 .iter()
388 .map(|name| {
389 (
390 name.to_owned(),
391 (
392 self.named.remove(name).unwrap(),
393 other.named.remove(name).unwrap(),
394 ),
395 )
396 })
397 .collect(),
398 named_order: self.named_order,
399 })
400 }
401}
402
403impl<T: std::fmt::Display> std::fmt::Display for Tuple<T> {
404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405 write!(f, "(")?;
406 {
407 if !self.is_empty() {
408 writeln!(f)?;
409 }
410 let mut f = pad_adapter::PadAdapter::new(f);
411 for field in &self.unnamed {
412 writeln!(f, "{field},")?;
413 }
414 for name in &self.named_order {
415 let field = &self.named[name];
416 writeln!(f, ".{name} = {field},")?;
417 }
418 }
419 write!(f, ")")?;
420 Ok(())
421 }
422}
423
424pub struct NamedTupleFmt<'a, T> {
425 name: &'a str,
426 tuple: &'a Tuple<T>,
427}
428
429impl<T: std::fmt::Display> std::fmt::Display for NamedTupleFmt<'_, T> {
430 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
431 write!(f, "{} {}", self.name, self.tuple)
432 }
433}