Skip to main content

nu_protocol/value/
record.rs

1//! Our insertion ordered map-type [`Record`]
2use std::{
3    fmt::Debug,
4    iter::FusedIterator,
5    marker::PhantomData,
6    ops::{Deref, DerefMut, RangeBounds},
7};
8
9use crate::{
10    CollectionColumns, CompareTypes, ShellError, Span, Type, TypeRelation, Value,
11    casing::{CaseInsensitive, CaseSensitive, CaseSensitivity, Casing, WrapCased},
12};
13
14use serde::{Deserialize, Serialize, de::Visitor, ser::SerializeMap};
15
16#[derive(Clone, Default, PartialEq)]
17pub struct Record {
18    inner: Vec<(String, Value)>,
19}
20
21impl Debug for Record {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        f.debug_map()
24            .entries(self.inner.iter().map(|(k, v)| (k, v)))
25            .finish()
26    }
27}
28
29/// A wrapper around [`Record`] that handles lookups. Whether the keys are compared case sensitively
30/// or not is controlled with the `Sensitivity` parameter.
31///
32/// It is never actually constructed as a value and only used as a reference to an existing [`Record`].
33#[repr(transparent)]
34pub struct CasedRecord<Sensitivity: CaseSensitivity>(Record, PhantomData<Sensitivity>);
35
36impl<Sensitivity: CaseSensitivity> CasedRecord<Sensitivity> {
37    #[inline]
38    const fn from_record(record: &Record) -> &Self {
39        // SAFETY: `CasedRecord` has the same memory layout as `Record`.
40        unsafe { &*(record as *const Record as *const Self) }
41    }
42
43    #[inline]
44    const fn from_record_mut(record: &mut Record) -> &mut Self {
45        // SAFETY: `CasedRecord` has the same memory layout as `Record`.
46        unsafe { &mut *(record as *mut Record as *mut Self) }
47    }
48
49    pub fn index_of(&self, col: impl AsRef<str>) -> Option<usize> {
50        let col = col.as_ref();
51        self.0.columns().rposition(|k| Sensitivity::eq(k, col))
52    }
53
54    pub fn contains(&self, col: impl AsRef<str>) -> bool {
55        self.index_of(col.as_ref()).is_some()
56    }
57
58    pub fn get(&self, col: impl AsRef<str>) -> Option<&Value> {
59        let index = self.index_of(col.as_ref())?;
60        Some(self.0.get_index(index)?.1)
61    }
62
63    pub fn get_mut(&mut self, col: impl AsRef<str>) -> Option<&mut Value> {
64        let index = self.index_of(col.as_ref())?;
65        Some(self.0.get_index_mut(index)?.1)
66    }
67
68    /// Remove single value by key and return it
69    pub fn remove(&mut self, col: impl AsRef<str>) -> Option<Value> {
70        let index = self.index_of(col.as_ref())?;
71        Some(self.0.remove_index(index))
72    }
73
74    /// Insert into the record, replacing preexisting value if found.
75    ///
76    /// Returns `Some(previous_value)` if found. Else `None`
77    pub fn insert<K>(&mut self, col: K, val: Value) -> Option<Value>
78    where
79        K: AsRef<str> + Into<String>,
80    {
81        if let Some(curr_val) = self.get_mut(col.as_ref()) {
82            Some(std::mem::replace(curr_val, val))
83        } else {
84            self.0.push(col, val);
85            None
86        }
87    }
88}
89
90impl<'a> WrapCased for &'a Record {
91    type Wrapper<S: CaseSensitivity> = &'a CasedRecord<S>;
92
93    #[inline]
94    fn case_sensitive(self) -> Self::Wrapper<CaseSensitive> {
95        CasedRecord::<CaseSensitive>::from_record(self)
96    }
97
98    #[inline]
99    fn case_insensitive(self) -> Self::Wrapper<CaseInsensitive> {
100        CasedRecord::<CaseInsensitive>::from_record(self)
101    }
102}
103
104impl<'a> WrapCased for &'a mut Record {
105    type Wrapper<S: CaseSensitivity> = &'a mut CasedRecord<S>;
106
107    #[inline]
108    fn case_sensitive(self) -> Self::Wrapper<CaseSensitive> {
109        CasedRecord::<CaseSensitive>::from_record_mut(self)
110    }
111
112    #[inline]
113    fn case_insensitive(self) -> Self::Wrapper<CaseInsensitive> {
114        CasedRecord::<CaseInsensitive>::from_record_mut(self)
115    }
116}
117
118impl AsRef<Record> for Record {
119    fn as_ref(&self) -> &Record {
120        self
121    }
122}
123
124impl AsMut<Record> for Record {
125    fn as_mut(&mut self) -> &mut Record {
126        self
127    }
128}
129
130impl Deref for Record {
131    type Target = CasedRecord<CaseSensitive>;
132
133    fn deref(&self) -> &Self::Target {
134        self.case_sensitive()
135    }
136}
137
138impl DerefMut for Record {
139    fn deref_mut(&mut self) -> &mut Self::Target {
140        self.case_sensitive()
141    }
142}
143
144/// A wrapper around [`Record`] that affects whether key comparisons are case sensitive or not.
145///
146/// Implements commonly used methods of [`Record`].
147pub struct DynCasedRecord<R> {
148    record: R,
149    casing: Casing,
150}
151
152impl Clone for DynCasedRecord<&Record> {
153    fn clone(&self) -> Self {
154        *self
155    }
156}
157
158impl Copy for DynCasedRecord<&Record> {}
159
160impl<'a> DynCasedRecord<&'a Record> {
161    pub fn index_of(self, col: impl AsRef<str>) -> Option<usize> {
162        match self.casing {
163            Casing::Sensitive => self.record.case_sensitive().index_of(col.as_ref()),
164            Casing::Insensitive => self.record.case_insensitive().index_of(col.as_ref()),
165        }
166    }
167
168    pub fn contains(self, col: impl AsRef<str>) -> bool {
169        self.get(col.as_ref()).is_some()
170    }
171
172    pub fn get(self, col: impl AsRef<str>) -> Option<&'a Value> {
173        match self.casing {
174            Casing::Sensitive => self.record.case_sensitive().get(col.as_ref()),
175            Casing::Insensitive => self.record.case_insensitive().get(col.as_ref()),
176        }
177    }
178}
179
180impl<'a> DynCasedRecord<&'a mut Record> {
181    /// Explicit reborrowing. See [Self::reborrow_mut()]
182    pub fn reborrow(&self) -> DynCasedRecord<&Record> {
183        DynCasedRecord {
184            record: &*self.record,
185            casing: self.casing,
186        }
187    }
188
189    /// Explicit reborrowing. Using this before methods that receive `self` is necessary to avoid
190    /// consuming the `DynCasedRecord` instance.
191    ///
192    /// ```
193    /// use nu_protocol::{record, record::{Record, DynCasedRecord}, Value, casing::Casing};
194    ///
195    /// let mut rec = record!{
196    ///     "A" => Value::test_nothing(),
197    ///     "B" => Value::test_int(42),
198    ///     "C" => Value::test_nothing(),
199    ///     "D" => Value::test_int(42),
200    /// };
201    /// let mut cased_rec: DynCasedRecord<&mut Record> = rec.cased_mut(Casing::Insensitive);
202    /// ```
203    ///
204    /// The following will fail to compile:
205    ///
206    /// ```compile_fail
207    /// # use nu_protocol::{record, record::{Record, DynCasedRecord}, Value, casing::Casing};
208    /// # let mut rec = record!{};
209    /// # let mut cased_rec: DynCasedRecord<&mut Record> = rec.cased_mut(Casing::Insensitive);
210    /// let a = cased_rec.get_mut("a");
211    /// let b = cased_rec.get_mut("b");
212    /// ```
213    ///
214    /// This is due to the fact `.get_mut()` receives `self`[^self] _by value_, which limits its use to
215    /// just once, unless we construct a new `DynCasedRecord`.
216    ///
217    /// [^self]: Receiving `&mut self` works, but has an undesirable effect on the return value's
218    /// lifetime. With `Self == &'wrapper mut DynCasedRecord<&'source mut Record>`, return value's
219    /// lifetime will be `'wrapper` rather than `'source`.
220    ///
221    /// We can create a new `DynCasedRecord<&mut Record>` from an existing one even though `&mut T` is
222    /// not [`Copy`]. This is accomplished with [reborrowing] which happens implicitly with native
223    /// references. Reborrowing also happens to be a tragically under documented feature of rust.
224    ///
225    /// Though there isn't a trait for it yet, it's possible and simple to implement, it just has
226    /// to be called explicitly:
227    ///
228    /// ```
229    /// # use nu_protocol::{record, record::{Record, DynCasedRecord}, Value, casing::Casing};
230    /// # let mut rec = record!{};
231    /// # let mut cased_rec: DynCasedRecord<&mut Record> = rec.cased_mut(Casing::Insensitive);
232    /// let a = cased_rec.reborrow_mut().get_mut("a");
233    /// let b = cased_rec.reborrow_mut().get_mut("b");
234    /// ```
235    ///
236    /// [reborrowing]: https://quinedot.github.io/rust-learning/st-reborrow.html
237    pub fn reborrow_mut(&mut self) -> DynCasedRecord<&mut Record> {
238        DynCasedRecord {
239            record: &mut *self.record,
240            casing: self.casing,
241        }
242    }
243
244    pub fn get_mut(self, col: impl AsRef<str>) -> Option<&'a mut Value> {
245        match self.casing {
246            Casing::Sensitive => self.record.case_sensitive().get_mut(col.as_ref()),
247            Casing::Insensitive => self.record.case_insensitive().get_mut(col.as_ref()),
248        }
249    }
250
251    pub fn remove(self, col: impl AsRef<str>) -> Option<Value> {
252        match self.casing {
253            Casing::Sensitive => self.record.case_sensitive().remove(col.as_ref()),
254            Casing::Insensitive => self.record.case_insensitive().remove(col.as_ref()),
255        }
256    }
257
258    /// Insert into the record, replacing preexisting value if found.
259    ///
260    /// Returns `Some(previous_value)` if found. Else `None`
261    pub fn insert<K>(self, col: K, val: Value) -> Option<Value>
262    where
263        K: AsRef<str> + Into<String>,
264    {
265        match self.casing {
266            Casing::Sensitive => self.record.case_sensitive().insert(col.as_ref(), val),
267            Casing::Insensitive => self.record.case_insensitive().insert(col.as_ref(), val),
268        }
269    }
270}
271
272impl Record {
273    pub fn new() -> Self {
274        Self::default()
275    }
276
277    pub fn with_capacity(capacity: usize) -> Self {
278        Self {
279            inner: Vec::with_capacity(capacity),
280        }
281    }
282
283    /// Returns an estimate of the memory size used by this Record in bytes
284    pub fn memory_size(&self) -> usize {
285        std::mem::size_of::<Self>()
286            + self
287                .inner
288                .iter()
289                .map(|(k, v)| k.capacity() + v.memory_size())
290                .sum::<usize>()
291    }
292
293    pub fn cased(&self, casing: Casing) -> DynCasedRecord<&Record> {
294        DynCasedRecord {
295            record: self,
296            casing,
297        }
298    }
299
300    pub fn cased_mut(&mut self, casing: Casing) -> DynCasedRecord<&mut Record> {
301        DynCasedRecord {
302            record: self,
303            casing,
304        }
305    }
306
307    /// Create a [`Record`] from a `Vec` of columns and a `Vec` of [`Value`]s
308    ///
309    /// Returns an error if `cols` and `vals` have different lengths.
310    ///
311    /// For perf reasons, this will not validate the rest of the record assumptions:
312    /// - unique keys
313    pub fn from_raw_cols_vals(
314        cols: Vec<String>,
315        vals: Vec<Value>,
316        input_span: Span,
317        creation_site_span: Span,
318    ) -> Result<Self, ShellError> {
319        if cols.len() == vals.len() {
320            let inner = cols.into_iter().zip(vals).collect();
321            Ok(Self { inner })
322        } else {
323            Err(ShellError::RecordColsValsMismatch {
324                bad_value: input_span,
325                creation_site: creation_site_span,
326            })
327        }
328    }
329
330    pub fn iter(&self) -> Iter<'_> {
331        self.into_iter()
332    }
333
334    pub fn iter_mut(&mut self) -> IterMut<'_> {
335        self.into_iter()
336    }
337
338    pub fn is_empty(&self) -> bool {
339        self.inner.is_empty()
340    }
341
342    pub fn len(&self) -> usize {
343        self.inner.len()
344    }
345
346    /// Naive push to the end of the datastructure.
347    ///
348    /// <div class="warning">
349    /// May duplicate data!
350    ///
351    /// Consider using [`CasedRecord::insert`] or [`DynCasedRecord::insert`] instead.
352    /// </div>
353    pub fn push(&mut self, col: impl Into<String>, val: Value) {
354        self.inner.push((col.into(), val));
355    }
356
357    pub fn get_index(&self, idx: usize) -> Option<(&String, &Value)> {
358        self.inner.get(idx).map(|(col, val): &(_, _)| (col, val))
359    }
360
361    pub fn get_index_mut(&mut self, idx: usize) -> Option<(&mut String, &mut Value)> {
362        self.inner.get_mut(idx).map(|(col, val)| (col, val))
363    }
364
365    /// Remove single value by index
366    fn remove_index(&mut self, index: usize) -> Value {
367        self.inner.remove(index).1
368    }
369
370    /// Remove elements in-place that do not satisfy `keep`
371    ///
372    /// ```rust
373    /// use nu_protocol::{record, Value};
374    ///
375    /// let mut rec = record!(
376    ///     "a" => Value::test_nothing(),
377    ///     "b" => Value::test_int(42),
378    ///     "c" => Value::test_nothing(),
379    ///     "d" => Value::test_int(42),
380    /// );
381    /// rec.retain(|_k, val| !val.is_nothing());
382    /// let mut iter_rec = rec.columns();
383    /// assert_eq!(iter_rec.next().map(String::as_str), Some("b"));
384    /// assert_eq!(iter_rec.next().map(String::as_str), Some("d"));
385    /// assert_eq!(iter_rec.next(), None);
386    /// ```
387    pub fn retain<F>(&mut self, mut keep: F)
388    where
389        F: FnMut(&str, &Value) -> bool,
390    {
391        self.retain_mut(|k, v| keep(k, v));
392    }
393
394    /// Remove elements in-place that do not satisfy `keep` while allowing mutation of the value.
395    ///
396    /// This can for example be used to recursively prune nested records.
397    ///
398    /// ```rust
399    /// use nu_protocol::{record, Record, Value};
400    ///
401    /// fn remove_foo_recursively(val: &mut Value) {
402    ///     if let Value::Record {val, ..} = val {
403    ///         val.to_mut().retain_mut(keep_non_foo);
404    ///     }
405    /// }
406    ///
407    /// fn keep_non_foo(k: &str, v: &mut Value) -> bool {
408    ///     if k == "foo" {
409    ///         return false;
410    ///     }
411    ///     remove_foo_recursively(v);
412    ///     true
413    /// }
414    ///
415    /// let mut test = Value::test_record(record!(
416    ///     "foo" => Value::test_nothing(),
417    ///     "bar" => Value::test_record(record!(
418    ///         "foo" => Value::test_nothing(),
419    ///         "baz" => Value::test_nothing(),
420    ///         ))
421    ///     ));
422    ///
423    /// remove_foo_recursively(&mut test);
424    /// let expected = Value::test_record(record!(
425    ///     "bar" => Value::test_record(record!(
426    ///         "baz" => Value::test_nothing(),
427    ///         ))
428    ///     ));
429    /// assert_eq!(test, expected);
430    /// ```
431    pub fn retain_mut<F>(&mut self, mut keep: F)
432    where
433        F: FnMut(&str, &mut Value) -> bool,
434    {
435        self.inner.retain_mut(|(col, val)| keep(col, val));
436    }
437
438    /// Truncate record to the first `len` elements.
439    ///
440    /// `len > self.len()` will be ignored
441    ///
442    /// ```rust
443    /// use nu_protocol::{record, Value};
444    ///
445    /// let mut rec = record!(
446    ///     "a" => Value::test_nothing(),
447    ///     "b" => Value::test_int(42),
448    ///     "c" => Value::test_nothing(),
449    ///     "d" => Value::test_int(42),
450    /// );
451    /// rec.truncate(42); // this is fine
452    /// assert_eq!(rec.columns().map(String::as_str).collect::<String>(), "abcd");
453    /// rec.truncate(2); // truncate
454    /// assert_eq!(rec.columns().map(String::as_str).collect::<String>(), "ab");
455    /// rec.truncate(0); // clear the record
456    /// assert_eq!(rec.len(), 0);
457    /// ```
458    pub fn truncate(&mut self, len: usize) {
459        self.inner.truncate(len);
460    }
461
462    pub fn truncate_front(&mut self, len: usize) {
463        if self.len() < len {
464            return;
465        }
466        let drop = self.len() - len;
467        self.inner.drain(..drop);
468    }
469
470    pub fn columns(&self) -> Columns<'_> {
471        Columns {
472            iter: self.inner.iter(),
473        }
474    }
475
476    pub fn into_columns(self) -> IntoColumns {
477        IntoColumns {
478            iter: self.inner.into_iter(),
479        }
480    }
481
482    pub fn values(&self) -> Values<'_> {
483        Values {
484            iter: self.inner.iter(),
485        }
486    }
487
488    pub fn into_values(self) -> IntoValues {
489        IntoValues {
490            iter: self.inner.into_iter(),
491        }
492    }
493
494    /// Obtain an iterator to remove elements in `range`
495    ///
496    /// Elements not consumed from the iterator will be dropped
497    ///
498    /// ```rust
499    /// use nu_protocol::{record, Value};
500    ///
501    /// let mut rec = record!(
502    ///     "a" => Value::test_nothing(),
503    ///     "b" => Value::test_int(42),
504    ///     "c" => Value::test_string("foo"),
505    /// );
506    /// {
507    ///     let mut drainer = rec.drain(1..);
508    ///     assert_eq!(drainer.next(), Some(("b".into(), Value::test_int(42))));
509    ///     // Dropping the `Drain`
510    /// }
511    /// let mut rec_iter = rec.into_iter();
512    /// assert_eq!(rec_iter.next(), Some(("a".into(), Value::test_nothing())));
513    /// assert_eq!(rec_iter.next(), None);
514    /// ```
515    pub fn drain<R>(&mut self, range: R) -> Drain<'_>
516    where
517        R: RangeBounds<usize> + Clone,
518    {
519        Drain {
520            iter: self.inner.drain(range),
521        }
522    }
523
524    /// Sort the record by its columns.
525    ///
526    /// ```rust
527    /// use nu_protocol::{record, Value};
528    ///
529    /// let mut rec = record!(
530    ///     "c" => Value::test_string("foo"),
531    ///     "b" => Value::test_int(42),
532    ///     "a" => Value::test_nothing(),
533    /// );
534    ///
535    /// rec.sort_cols();
536    ///
537    /// assert_eq!(
538    ///     Value::test_record(rec),
539    ///     Value::test_record(record!(
540    ///         "a" => Value::test_nothing(),
541    ///         "b" => Value::test_int(42),
542    ///         "c" => Value::test_string("foo"),
543    ///     ))
544    /// );
545    /// ```
546    pub fn sort_cols(&mut self) {
547        self.inner.sort_by(|(k1, _), (k2, _)| k1.cmp(k2))
548    }
549}
550
551impl CompareTypes<CollectionColumns<Type>> for Record {
552    fn compare_types(&self, other: &CollectionColumns<Type>) -> Option<TypeRelation> {
553        match (self.is_empty(), other.is_empty()) {
554            (true, true) => return Some(TypeRelation::Equal),
555            (true, false) => return Some(TypeRelation::Supertype),
556            (false, true) => return Some(TypeRelation::Subtype),
557            (false, false) => {}
558        }
559
560        let (flipped, eq) = match self.len().cmp(&other.len()) {
561            std::cmp::Ordering::Less => (false, false),
562            std::cmp::Ordering::Equal => (false, true),
563            std::cmp::Ordering::Greater => (true, false),
564        };
565
566        let start = match eq {
567            true => TypeRelation::Equal,
568            false => TypeRelation::Supertype,
569        };
570
571        if flipped {
572            let lhs = other;
573            let rhs = self;
574            lhs.iter()
575                .map(|(lhs_key, lhs_ty)| {
576                    match rhs.get(lhs_key) {
577                        Some(rhs_val) => {
578                            if CompareTypes::<Type>::is_any(lhs_ty) || rhs_val.is_any() {
579                                // Not really" equal", just used to continue without affecting the outcome.
580                                Some(TypeRelation::Equal)
581                            } else {
582                                // `CompareTypes<Value> for Type` is not implemented
583                                // lhs_ty.compare_types(rhs_val)
584                                rhs_val.compare_types(lhs_ty).map(TypeRelation::reverse)
585                            }
586                        }
587                        None => None,
588                    }
589                })
590                .try_fold(start, |acc, e| acc.combine(e?))
591                .map(TypeRelation::reverse)
592        } else {
593            let lhs = self;
594            let rhs = other;
595            lhs.iter()
596                .map(|(lhs_key, lhs_val)| {
597                    match rhs.get(lhs_key) {
598                        Some(rhs_ty) => {
599                            if lhs_val.is_any() || CompareTypes::<Type>::is_any(rhs_ty) {
600                                // Not really" equal", just used to continue without affecting the outcome.
601                                Some(TypeRelation::Equal)
602                            } else {
603                                lhs_val.compare_types(rhs_ty)
604                            }
605                        }
606                        None => None,
607                    }
608                })
609                .try_fold(start, |acc, e| acc.combine(e?))
610        }
611    }
612}
613
614impl Serialize for Record {
615    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
616    where
617        S: serde::Serializer,
618    {
619        let mut map = serializer.serialize_map(Some(self.len()))?;
620        for (k, v) in self {
621            map.serialize_entry(k, v)?;
622        }
623        map.end()
624    }
625}
626
627impl<'de> Deserialize<'de> for Record {
628    /// Special deserialization implementation that turns a map-pattern into a [`Record`]
629    ///
630    /// Denies duplicate keys
631    ///
632    /// ```rust
633    /// use serde_json::{from_str, Result};
634    /// use nu_protocol::{Record, Value, record};
635    ///
636    /// // A `Record` in json is a Record with a packed `Value`
637    /// // The `Value` record has a single key indicating its type and the inner record describing
638    /// // its representation of value and the associated `Span`
639    /// let ok = r#"{"a": {"Int": {"val": 42, "span": {"start": 0, "end": 0}}},
640    ///              "b": {"Int": {"val": 37, "span": {"start": 0, "end": 0}}}}"#;
641    /// let ok_rec: Record = from_str(ok).unwrap();
642    /// assert_eq!(Value::test_record(ok_rec),
643    ///            Value::test_record(record!{"a" => Value::test_int(42),
644    ///                                       "b" => Value::test_int(37)}));
645    /// // A repeated key will lead to a deserialization error
646    /// let bad = r#"{"a": {"Int": {"val": 42, "span": {"start": 0, "end": 0}}},
647    ///               "a": {"Int": {"val": 37, "span": {"start": 0, "end": 0}}}}"#;
648    /// let bad_rec: Result<Record> = from_str(bad);
649    /// assert!(bad_rec.is_err());
650    /// ```
651    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
652    where
653        D: serde::Deserializer<'de>,
654    {
655        deserializer.deserialize_map(RecordVisitor)
656    }
657}
658
659struct RecordVisitor;
660
661impl<'de> Visitor<'de> for RecordVisitor {
662    type Value = Record;
663
664    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
665        formatter.write_str("a nushell `Record` mapping string keys/columns to nushell `Value`")
666    }
667
668    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
669    where
670        A: serde::de::MapAccess<'de>,
671    {
672        let mut record = Record::with_capacity(map.size_hint().unwrap_or(0));
673
674        while let Some((key, value)) = map.next_entry::<String, Value>()? {
675            if record.insert(key, value).is_some() {
676                return Err(serde::de::Error::custom(
677                    "invalid entry, duplicate keys are not allowed for `Record`",
678                ));
679            }
680        }
681
682        Ok(record)
683    }
684}
685
686impl FromIterator<(String, Value)> for Record {
687    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
688        // TODO: should this check for duplicate keys/columns?
689        Self {
690            inner: iter.into_iter().collect(),
691        }
692    }
693}
694
695impl Extend<(String, Value)> for Record {
696    fn extend<T: IntoIterator<Item = (String, Value)>>(&mut self, iter: T) {
697        for (k, v) in iter {
698            // TODO: should this .insert with a check?
699            self.push(k, v)
700        }
701    }
702}
703
704pub struct IntoIter {
705    iter: std::vec::IntoIter<(String, Value)>,
706}
707
708impl Iterator for IntoIter {
709    type Item = (String, Value);
710
711    fn next(&mut self) -> Option<Self::Item> {
712        self.iter.next()
713    }
714
715    fn size_hint(&self) -> (usize, Option<usize>) {
716        self.iter.size_hint()
717    }
718}
719
720impl DoubleEndedIterator for IntoIter {
721    fn next_back(&mut self) -> Option<Self::Item> {
722        self.iter.next_back()
723    }
724}
725
726impl ExactSizeIterator for IntoIter {
727    fn len(&self) -> usize {
728        self.iter.len()
729    }
730}
731
732impl FusedIterator for IntoIter {}
733
734impl IntoIterator for Record {
735    type Item = (String, Value);
736
737    type IntoIter = IntoIter;
738
739    fn into_iter(self) -> Self::IntoIter {
740        IntoIter {
741            iter: self.inner.into_iter(),
742        }
743    }
744}
745
746pub struct Iter<'a> {
747    iter: std::slice::Iter<'a, (String, Value)>,
748}
749
750impl<'a> Iterator for Iter<'a> {
751    type Item = (&'a String, &'a Value);
752
753    fn next(&mut self) -> Option<Self::Item> {
754        self.iter.next().map(|(col, val): &(_, _)| (col, val))
755    }
756
757    fn size_hint(&self) -> (usize, Option<usize>) {
758        self.iter.size_hint()
759    }
760}
761
762impl DoubleEndedIterator for Iter<'_> {
763    fn next_back(&mut self) -> Option<Self::Item> {
764        self.iter.next_back().map(|(col, val): &(_, _)| (col, val))
765    }
766}
767
768impl ExactSizeIterator for Iter<'_> {
769    fn len(&self) -> usize {
770        self.iter.len()
771    }
772}
773
774impl FusedIterator for Iter<'_> {}
775
776impl<'a> IntoIterator for &'a Record {
777    type Item = (&'a String, &'a Value);
778
779    type IntoIter = Iter<'a>;
780
781    fn into_iter(self) -> Self::IntoIter {
782        Iter {
783            iter: self.inner.iter(),
784        }
785    }
786}
787
788pub struct IterMut<'a> {
789    iter: std::slice::IterMut<'a, (String, Value)>,
790}
791
792impl<'a> Iterator for IterMut<'a> {
793    type Item = (&'a String, &'a mut Value);
794
795    fn next(&mut self) -> Option<Self::Item> {
796        self.iter.next().map(|(col, val)| (&*col, val))
797    }
798
799    fn size_hint(&self) -> (usize, Option<usize>) {
800        self.iter.size_hint()
801    }
802}
803
804impl DoubleEndedIterator for IterMut<'_> {
805    fn next_back(&mut self) -> Option<Self::Item> {
806        self.iter.next_back().map(|(col, val)| (&*col, val))
807    }
808}
809
810impl ExactSizeIterator for IterMut<'_> {
811    fn len(&self) -> usize {
812        self.iter.len()
813    }
814}
815
816impl FusedIterator for IterMut<'_> {}
817
818impl<'a> IntoIterator for &'a mut Record {
819    type Item = (&'a String, &'a mut Value);
820
821    type IntoIter = IterMut<'a>;
822
823    fn into_iter(self) -> Self::IntoIter {
824        IterMut {
825            iter: self.inner.iter_mut(),
826        }
827    }
828}
829
830pub struct Columns<'a> {
831    iter: std::slice::Iter<'a, (String, Value)>,
832}
833
834impl<'a> Iterator for Columns<'a> {
835    type Item = &'a String;
836
837    fn next(&mut self) -> Option<Self::Item> {
838        self.iter.next().map(|(col, _)| col)
839    }
840
841    fn size_hint(&self) -> (usize, Option<usize>) {
842        self.iter.size_hint()
843    }
844}
845
846impl DoubleEndedIterator for Columns<'_> {
847    fn next_back(&mut self) -> Option<Self::Item> {
848        self.iter.next_back().map(|(col, _)| col)
849    }
850}
851
852impl ExactSizeIterator for Columns<'_> {
853    fn len(&self) -> usize {
854        self.iter.len()
855    }
856}
857
858impl FusedIterator for Columns<'_> {}
859
860pub struct IntoColumns {
861    iter: std::vec::IntoIter<(String, Value)>,
862}
863
864impl Iterator for IntoColumns {
865    type Item = String;
866
867    fn next(&mut self) -> Option<Self::Item> {
868        self.iter.next().map(|(col, _)| col)
869    }
870
871    fn size_hint(&self) -> (usize, Option<usize>) {
872        self.iter.size_hint()
873    }
874}
875
876impl DoubleEndedIterator for IntoColumns {
877    fn next_back(&mut self) -> Option<Self::Item> {
878        self.iter.next_back().map(|(col, _)| col)
879    }
880}
881
882impl ExactSizeIterator for IntoColumns {
883    fn len(&self) -> usize {
884        self.iter.len()
885    }
886}
887
888impl FusedIterator for IntoColumns {}
889
890pub struct Values<'a> {
891    iter: std::slice::Iter<'a, (String, Value)>,
892}
893
894impl<'a> Iterator for Values<'a> {
895    type Item = &'a Value;
896
897    fn next(&mut self) -> Option<Self::Item> {
898        self.iter.next().map(|(_, val)| val)
899    }
900
901    fn size_hint(&self) -> (usize, Option<usize>) {
902        self.iter.size_hint()
903    }
904}
905
906impl DoubleEndedIterator for Values<'_> {
907    fn next_back(&mut self) -> Option<Self::Item> {
908        self.iter.next_back().map(|(_, val)| val)
909    }
910}
911
912impl ExactSizeIterator for Values<'_> {
913    fn len(&self) -> usize {
914        self.iter.len()
915    }
916}
917
918impl FusedIterator for Values<'_> {}
919
920pub struct IntoValues {
921    iter: std::vec::IntoIter<(String, Value)>,
922}
923
924impl Iterator for IntoValues {
925    type Item = Value;
926
927    fn next(&mut self) -> Option<Self::Item> {
928        self.iter.next().map(|(_, val)| val)
929    }
930
931    fn size_hint(&self) -> (usize, Option<usize>) {
932        self.iter.size_hint()
933    }
934}
935
936impl DoubleEndedIterator for IntoValues {
937    fn next_back(&mut self) -> Option<Self::Item> {
938        self.iter.next_back().map(|(_, val)| val)
939    }
940}
941
942impl ExactSizeIterator for IntoValues {
943    fn len(&self) -> usize {
944        self.iter.len()
945    }
946}
947
948impl FusedIterator for IntoValues {}
949
950pub struct Drain<'a> {
951    iter: std::vec::Drain<'a, (String, Value)>,
952}
953
954impl Iterator for Drain<'_> {
955    type Item = (String, Value);
956
957    fn next(&mut self) -> Option<Self::Item> {
958        self.iter.next()
959    }
960
961    fn size_hint(&self) -> (usize, Option<usize>) {
962        self.iter.size_hint()
963    }
964}
965
966impl DoubleEndedIterator for Drain<'_> {
967    fn next_back(&mut self) -> Option<Self::Item> {
968        self.iter.next_back()
969    }
970}
971
972impl ExactSizeIterator for Drain<'_> {
973    fn len(&self) -> usize {
974        self.iter.len()
975    }
976}
977
978impl FusedIterator for Drain<'_> {}
979
980#[macro_export]
981macro_rules! record {
982    // The macro only compiles if the number of columns equals the number of values,
983    // so it's safe to call `unwrap` below.
984    {$($col:expr => $val:expr),+ $(,)?} => {
985        $crate::Record::from_raw_cols_vals(
986            ::std::vec![$($col.into(),)+],
987            ::std::vec![$($val,)+],
988            $crate::Span::unknown(),
989            $crate::Span::unknown(),
990        ).unwrap()
991    };
992    {} => {
993        $crate::Record::new()
994    };
995}
996
997/// Helper for constructing [Value::Record] instances for use in tests and
998/// [Example](crate::Example)s
999/// ```
1000/// # use nu_protocol::{Value, test_record, record};
1001/// let test = test_record! {
1002///     "a" => "foo",
1003///     "b" => 42,
1004///     "c" => [1, 2, 3],
1005/// };
1006///
1007/// let expected = Value::test_record(record! {
1008///     "a" => Value::test_string("foo"),
1009///     "b" => Value::test_int(42),
1010///     "c" => Value::test_list(vec![
1011///         Value::test_int(1),
1012///         Value::test_int(2),
1013///         Value::test_int(3),
1014///     ]),
1015/// });
1016///
1017/// assert_eq!(test, expected);
1018/// ```
1019#[macro_export]
1020macro_rules! test_record {
1021    {$($col:expr => $val:expr),+ $(,)?} => {
1022        $crate::Value::test_record($crate::record! {
1023            $($col => $crate::IntoValue::into_value($val, $crate::Span::test_data())),+
1024        })
1025    };
1026    {} => {
1027        record! {}
1028    };
1029}
1030
1031#[doc(hidden)]
1032pub const fn count_helper<const N: usize>(_: [(); N]) -> usize {
1033    N
1034}
1035
1036/// Helper for constructing table (list of records) values for use in tests and
1037/// [Example](crate::Example)s
1038/// ```
1039/// # use nu_protocol::{Value, test_table, test_record, record};
1040/// let test = test_table![
1041///     ["a", "b", "c"];
1042///     [1, 2, 3],
1043///     [4, 5, 6],
1044/// ];
1045///
1046/// let expected = Value::test_list(vec![
1047///     test_record! {"a" => 1, "b" => 2, "c" => 3},
1048///     test_record! {"a" => 4, "b" => 5, "c" => 6},
1049/// ]);
1050///
1051/// assert_eq!(test, expected);
1052/// ```
1053#[macro_export]
1054macro_rules! test_table {
1055    (@replace_expr $_t:tt $sub:expr) => { $sub };
1056    (@count_tts $($smth:tt)*) => {
1057        $crate::record::count_helper([$($crate::test_table!(@replace_expr $smth ())),*])
1058    };
1059    [[$($col:expr),+ $(,)?]; $([$($val:expr),+ $(,)?]),+ $(,)?] => {{
1060        const COLUMNS: usize = $crate::test_table!(@count_tts $($col)+);
1061        let columns: ::std::vec::Vec<::std::string::String> = ::std::vec![$($col.into()),+];
1062        let rows = vec![ $(
1063            {
1064                const ROW_ITEMS: usize = $crate::test_table!(@count_tts $($val)+);
1065                const _: () = assert!(ROW_ITEMS == COLUMNS) ;
1066                $crate::Value::test_record($crate::Record::from_raw_cols_vals(
1067                    columns.clone(),
1068                    ::std::vec![ $(
1069                        $crate::IntoValue::into_value($val, $crate::Span::test_data())
1070                    ),+ ],
1071                    $crate::Span::test_data(),
1072                    $crate::Span::test_data(),
1073                ).expect("Number of columns and rows should be equal"))
1074            }
1075        ),+ ];
1076        $crate::Value::test_list(rows)
1077    }};
1078}