amadeus_types/
group.rs

1//! Implement [`Record`] for [`Group`] aka [`Row`].
2
3use fxhash::FxBuildHasher;
4use hashlink::LinkedHashMap;
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use std::{
7	cmp::Ordering, fmt::{self, Debug}, ops::Index, slice::SliceIndex, str, sync::Arc
8};
9
10use super::{util::IteratorExt, AmadeusOrd, Downcast, DowncastError, DowncastFrom, Value};
11
12/// Corresponds to Parquet groups of named fields.
13///
14/// Its fields can be accessed by name via
15/// [`get()`](Group::get)/[`get_mut()`](Self::get_mut) and via name or ordinal with
16/// [`group[index]`](#impl-Index<usize>).
17#[derive(Clone, PartialEq)]
18pub struct Group {
19	fields: Vec<Value>,
20	field_names: Option<Arc<LinkedHashMap<String, usize, FxBuildHasher>>>,
21}
22
23impl Group {
24	#[doc(hidden)]
25	pub fn new(
26		fields: Vec<Value>, field_names: Option<Arc<LinkedHashMap<String, usize, FxBuildHasher>>>,
27	) -> Self {
28		Self {
29			fields,
30			field_names,
31		}
32	}
33	#[doc(hidden)]
34	pub fn fields(&self) -> &[Value] {
35		&self.fields
36	}
37	#[doc(hidden)]
38	pub fn field_names(&self) -> Option<&Arc<LinkedHashMap<String, usize, FxBuildHasher>>> {
39		self.field_names.as_ref()
40	}
41	/// Get a reference to the value belonging to a particular field name. Returns `None`
42	/// if the field name doesn't exist.
43	pub fn get(&self, k: &str) -> Option<&Value> {
44		self.field_names
45			.as_ref()?
46			.get(k)
47			.map(|&offset| &self.fields[offset])
48	}
49	#[doc(hidden)]
50	pub fn into_fields(self) -> Vec<Value> {
51		self.fields
52	}
53}
54
55impl Serialize for Group {
56	fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
57	where
58		S: Serializer,
59	{
60		// <Self as SerdeData>::serialize(self, serializer)
61		unimplemented!()
62	}
63}
64impl<'de> Deserialize<'de> for Group {
65	fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
66	where
67		D: Deserializer<'de>,
68	{
69		// <Self as SerdeData>::deserialize(deserializer, None)
70		unimplemented!()
71	}
72}
73
74// impl From<Group> for internal::record::types::Group {
75// 	fn from(group: Group) -> Self {
76// 		let field_names = group.field_names();
77// 		Self::new(group.into_fields().map(Into::into), field_names)
78// 	}
79// }
80impl<I> Index<I> for Group
81where
82	I: SliceIndex<[Value]>,
83{
84	type Output = <I as SliceIndex<[Value]>>::Output;
85
86	fn index(&self, index: I) -> &Self::Output {
87		self.fields.index(index)
88	}
89}
90impl PartialOrd for Group {
91	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
92		if match (self.field_names.as_ref(), other.field_names.as_ref()) {
93			(Some(a), Some(b)) => a == b,
94			_ => self.fields.len() == other.fields.len(),
95		} {
96			self.fields.partial_cmp(&other.fields)
97		} else {
98			None
99		}
100	}
101}
102impl AmadeusOrd for Group {
103	fn amadeus_cmp(&self, other: &Self) -> Ordering {
104		match (self.field_names.as_ref(), other.field_names.as_ref()) {
105			(Some(a), Some(b)) => a
106				.iter()
107				.map(|(name, _index)| name)
108				.zip(&self.fields)
109				.cmp_by_(
110					b.iter().map(|(name, _index)| name).zip(&other.fields),
111					|a, b| a.amadeus_cmp(&b),
112				),
113			(None, None) => self
114				.fields
115				.iter()
116				.cmp_by_(&other.fields, AmadeusOrd::amadeus_cmp),
117			(Some(_), None) => Ordering::Less,
118			(None, Some(_)) => Ordering::Greater,
119		}
120	}
121}
122
123impl Debug for Group {
124	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125		if let Some(field_names) = self.field_names.as_ref() {
126			let mut printer = f.debug_struct("Group");
127			for (name, field) in field_names
128				.iter()
129				.map(|(name, _index)| name)
130				.zip(self.fields.iter())
131			{
132				let _ = printer.field(name, field);
133			}
134			printer.finish()
135		} else {
136			let mut printer = f.debug_tuple("Group");
137			for field in &self.fields {
138				let _ = printer.field(field);
139			}
140			printer.finish()
141		}
142	}
143}
144
145impl From<LinkedHashMap<String, Value, FxBuildHasher>> for Group {
146	fn from(hashmap: LinkedHashMap<String, Value, FxBuildHasher>) -> Self {
147		let mut keys = LinkedHashMap::with_capacity_and_hasher(hashmap.len(), Default::default());
148		Self::new(
149			hashmap
150				.into_iter()
151				.map(|(key, value)| {
152					if keys.insert(key, keys.len()).is_some() {
153						panic!("duplicate key");
154					}
155					value
156				})
157				.collect(),
158			Some(Arc::new(keys)),
159		)
160	}
161}
162
163macro_rules! tuple_downcast {
164	($len:tt $($t:ident $i:tt)*) => (
165		impl<$($t,)*> DowncastFrom<Group> for ($($t,)*) where $($t: DowncastFrom<Value>,)* {
166			fn downcast_from(self_: Group) -> Result<Self, DowncastError> {
167				#[allow(unused_mut, unused_variables)]
168				let mut fields = self_.into_fields().into_iter();
169				if fields.len() != $len {
170					return Err(DowncastError{from:"",to:""});
171				}
172				Ok(($({let _ = $i;fields.next().unwrap().downcast()?},)*))
173			}
174		}
175	);
176}
177tuple!(tuple_downcast);
178
179macro_rules! tuple_from {
180	($len:tt $($t:ident $i:tt)*) => (
181		impl<$($t,)*> From<($($t,)*)> for Group where $($t: Into<Value>,)* {
182			#[allow(unused_variables)]
183			fn from(value: ($($t,)*)) -> Self {
184				Group::new(vec![$(value.$i.into(),)*], None)
185			}
186		}
187	);
188}
189tuple!(tuple_from);
190
191// impl From<Group> for LinkedHashMap<String, Value, FxBuildHasher> {
192// 	fn from(group: Group) -> Self {
193// 		group
194// 			.field_names
195// 			.iter()
196// 			.map(|(name, _index)| name.clone())
197// 			.zip(group.fields)
198// 			.collect()
199// 	}
200// }