rline_api/
row.rs

1//! # row
2//!
3//! Module defining the Row struct, representing a dataset row.
4//!
5//! A `Row` in the dataset is a collection of named columns, each associated with a `Value`.
6//! This module provides functionality to create, manipulate, and convert rows.
7//!
8//! ## Examples
9//!
10//! Creating a new Row:
11//!
12//! ```rust
13//! use rline_api::row::Row;
14//! use rline_api::value::Value;
15//!
16//! let row = Row::from(vec![
17//!     ("name".to_string(), Value::String("Alice".to_string())),
18//!     ("age".to_string(), Value::Integer(30)),
19//! ]);
20//!
21//! assert_eq!(row.get("name"), Some(&Value::String("Alice".to_string())));
22//! assert_eq!(row.get("age"), Some(&Value::Integer(30)));
23//! ```
24//!
25//! Converting a Row into a serde_json::Value:
26//!
27//! ```rust
28//! use rline_api::row::Row;
29//! use rline_api::value::Value;
30//! use serde_json::json;
31//!
32//! let row = Row::from(vec![
33//!     ("name".to_string(), Value::String("Charlie".to_string())),
34//!     ("age".to_string(), Value::Integer(40)),
35//! ]);
36//!
37//! let json_value: serde_json::Value = row.into();
38//! assert_eq!(
39//!     json_value,
40//!     json!({
41//!         "name": "Charlie",
42//!         "age": 40
43//!     })
44//! );
45//! ```
46//!
47//! Retrieving values from a Row:
48//!
49//! ```rust
50//! use rline_api::row::Row;
51//! use rline_api::value::Value;
52//!
53//! let row = Row::from(vec![
54//!     ("name".to_string(), Value::String("Bob".to_string())),
55//!     ("age".to_string(), Value::Integer(25)),
56//! ]);
57//!
58//! assert_eq!(row.get("name"), Some(&Value::String("Bob".to_string())));
59//! assert_eq!(row.get("age"), Some(&Value::Integer(25)));
60//! assert_eq!(row.get("nonexistent"), None);
61//! ```
62//!
63//! ## Usage
64//!
65//! This module is used within the `rline_api` library to represent rows in datasets. Rows can be
66//! created, manipulated, and converted to various formats using the provided functions and methods.
67//! The `Row` struct and its associated types are integral to working with tabular data in the
68//! `rline_api` crate.
69//!
70//! ## License
71//!
72//! This module is part of the `rline_api` crate, licensed under the Apache-2.0 License.
73use std::collections::hash_map::{IntoIter, Iter};
74use std::collections::HashMap;
75use std::ops::{Deref, DerefMut};
76
77use bincode::config::{standard, Configuration, Fixint, LittleEndian};
78use bincode::{Decode as BincodeDecode, Encode as BincodeEncode};
79use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
80use serde_json::Value as SerdeJsonValue;
81
82use crate::rline_error::RlineError;
83use crate::rline_error::RlineError::RuntimeError;
84use crate::value::Value;
85
86type WrappedType = HashMap<String, Value>;
87
88const BINCODE_CONFIG: Configuration<LittleEndian, Fixint> = standard().with_fixed_int_encoding();
89
90/// A Row is a set of columns with their value. It associates column names with typed values.
91#[derive(
92    SerdeSerialize, SerdeDeserialize, BincodeDecode, BincodeEncode, Clone, Debug, PartialEq,
93)]
94pub struct Row(WrappedType);
95
96impl Row {
97    /// Creates an empty Row.
98    /// The Row is initially created with a capacity of 0,
99    /// so it will not allocate until it is first inserted into.
100    pub fn new() -> Self {
101        Row(HashMap::new())
102    }
103
104    /// Creates an empty Row with at least the specified capacity.
105    /// The Row will be able to hold at least capacity elements without reallocating.
106    /// This method is allowed to allocate for more elements than capacity.
107    /// If capacity is 0, the hash map will not allocate.
108    pub fn with_capacity(capacity: usize) -> Self {
109        Row(HashMap::with_capacity(capacity))
110    }
111}
112
113impl Default for Row {
114    /// Creates an empty Row.
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120impl Deref for Row {
121    type Target = WrappedType;
122    fn deref(&self) -> &Self::Target {
123        &self.0
124    }
125}
126
127impl DerefMut for Row {
128    fn deref_mut(&mut self) -> &mut WrappedType {
129        &mut self.0
130    }
131}
132
133type ConsumedItem = (String, Value);
134type BorrowedItem<'a> = (&'a String, &'a Value);
135
136impl IntoIterator for Row {
137    type Item = ConsumedItem;
138    type IntoIter = TableIntoIterator;
139
140    /// Creates a consuming iterator, that is, one that moves each column name-value pair out
141    /// of the Row in arbitrary order.
142    /// The Row cannot be used after calling this.
143    fn into_iter(self) -> Self::IntoIter {
144        TableIntoIterator {
145            iterator: self.0.into_iter(),
146        }
147    }
148}
149
150pub struct TableIntoIterator {
151    iterator: IntoIter<String, Value>,
152}
153
154impl Iterator for TableIntoIterator {
155    type Item = ConsumedItem;
156
157    /// Advances the iterator and returns the next value.
158    /// Returns None when iteration is finished.
159    fn next(&mut self) -> Option<ConsumedItem> {
160        self.iterator.next()
161    }
162}
163
164impl<'a> IntoIterator for &'a Row {
165    type Item = BorrowedItem<'a>;
166    type IntoIter = TableIterator<'a>;
167
168    /// An iterator visiting all column name-value pairs in arbitrary order.
169    fn into_iter(self) -> Self::IntoIter {
170        TableIterator {
171            iterator: self.0.iter(),
172        }
173    }
174}
175
176pub struct TableIterator<'a> {
177    iterator: Iter<'a, String, Value>,
178}
179
180impl<'a> Iterator for TableIterator<'a> {
181    type Item = BorrowedItem<'a>;
182
183    /// Advances the iterator and returns the next value.
184    /// Returns None when iteration is finished.
185    fn next(&mut self) -> Option<BorrowedItem<'a>> {
186        self.iterator.next()
187    }
188}
189
190/// Supported serialization format for row.
191#[derive(SerdeDeserialize)]
192pub enum SerializationFormat {
193    #[serde(alias = "json", alias = "JSON")]
194    Json,
195    #[serde(alias = "bincode", alias = "BINCODE")]
196    Bincode,
197}
198
199impl Row {
200    /// Serialize this row to bytes in json format.
201    pub fn to_bytes_json(&self) -> Result<Vec<u8>, RlineError> {
202        serde_json::to_vec(self).map_err(|e| RlineError::runtime_error(&e))
203    }
204
205    /// Serialize this row to bytes in bincode format.
206    pub fn to_bytes_bincode(&self) -> Result<Vec<u8>, RlineError> {
207        bincode::encode_to_vec(self, BINCODE_CONFIG).map_err(|e| RlineError::runtime_error(&e))
208    }
209
210    /// Serialize a Result<Row, String> to bytes in bincode format.
211    pub fn to_bytes_bincode_result(result: Result<Row, String>) -> Result<Vec<u8>, RlineError> {
212        bincode::encode_to_vec(result, BINCODE_CONFIG).map_err(|e| RlineError::runtime_error(&e))
213    }
214
215    /// Serialize a Result<Row, String> to bytes in json format.
216    pub fn to_bytes_json_result(result: Result<Row, String>) -> Result<Vec<u8>, RlineError> {
217        serde_json::to_vec(&result).map_err(|e| RlineError::runtime_error(&e))
218    }
219
220    /// Deserialize the bytes in json format.
221    pub fn from_bytes_json(from: &[u8]) -> Result<Self, RlineError> {
222        serde_json::from_slice(from).map_err(|e| RlineError::runtime_error(&e))
223    }
224
225    /// Deserialize the bytes in bincode format.
226    pub fn from_bytes_bincode(from: &[u8]) -> Result<Self, RlineError> {
227        let (decoded, _) = bincode::decode_from_slice(from, BINCODE_CONFIG)
228            .map_err(|e| RlineError::runtime_error(&e))?;
229        Ok(decoded)
230    }
231
232    /// Deserialize the bytes of a Result<Row, String> in json format.
233    pub fn from_bytes_json_result(from: &[u8]) -> Result<Self, RlineError> {
234        let decoded: Result<Self, String> =
235            serde_json::from_slice(from).map_err(|e| RlineError::runtime_error(&e))?;
236        decoded.map_err(RuntimeError)
237    }
238
239    /// Deserialize the bytes of a Result<Row, String> in bincode format.
240    pub fn from_bytes_bincode_result(from: &[u8]) -> Result<Self, RlineError> {
241        let (decoded, _): (Result<Self, String>, usize) =
242            bincode::decode_from_slice(from, BINCODE_CONFIG)
243                .map_err(|e| RlineError::runtime_error(&e))?;
244        decoded.map_err(RuntimeError)
245    }
246
247    fn json_value_to_row(json_value: SerdeJsonValue) -> Result<Row, RlineError> {
248        match json_value {
249            SerdeJsonValue::Null
250            | SerdeJsonValue::Bool(_)
251            | SerdeJsonValue::Number(_)
252            | SerdeJsonValue::String(_)
253            | SerdeJsonValue::Array(_) => Err(RuntimeError(
254                format!("Json value {} does not represent a row. A row is a map associating column names to their values.", json_value))
255            ),
256            SerdeJsonValue::Object(map_key_value) => {
257                let mut row = Row::with_capacity(map_key_value.len());
258                for (column_name, json_value) in map_key_value {
259                    row.insert(column_name, Value::from_json_value(json_value)?);
260                }
261                Ok(row)
262            }
263        }
264    }
265
266    /// Deserialize the bytes in json format infering the Value type from a json value
267    pub fn from_bytes_json_infer_types(from: &[u8]) -> Result<Vec<Row>, RlineError> {
268        let json_value: SerdeJsonValue =
269            serde_json::from_slice(from).map_err(|e| RlineError::runtime_error(&e))?;
270
271        match json_value {
272            SerdeJsonValue::Null
273            | SerdeJsonValue::Bool(_)
274            | SerdeJsonValue::Number(_)
275            | SerdeJsonValue::String(_)
276            | SerdeJsonValue::Object(_) => Err(RuntimeError(format!(
277                "Json value {} does not represent a list of ros.",
278                json_value
279            ))),
280            SerdeJsonValue::Array(values) => {
281                values.into_iter().map(Row::json_value_to_row).collect()
282            }
283        }
284    }
285}
286
287impl<const N: usize> From<[(String, Value); N]> for Row {
288    /// # Examples
289    ///
290    /// ```
291    /// use rline_api::row::Row;
292    /// use rline_api::value::Value;
293    ///
294    /// let table1 = Row::from([
295    ///   ("col1".to_string(), Value::from(42)),
296    ///   ("col2".to_string(), Value::from("Hello World !".to_string())),
297    /// ]);
298    /// let table2: Row = [
299    ///   ("col1".to_string(), Value::from(42)),
300    ///   ("col2".to_string(), Value::from("Hello World !".to_string())),
301    /// ].into();
302    /// assert_eq!(table1, table2);
303    /// ```
304    fn from(arr: [(String, Value); N]) -> Self {
305        Row(HashMap::from_iter(arr))
306    }
307}
308
309impl From<HashMap<String, Value>> for Row {
310    fn from(map: HashMap<String, Value>) -> Self {
311        Row(map)
312    }
313}