use std::{
iter::FusedIterator,
marker::PhantomData,
ops::{Deref, DerefMut, RangeBounds},
};
use crate::{
ShellError, Span, Value,
casing::{CaseInsensitive, CaseSensitive, CaseSensitivity, Casing, WrapCased},
};
use serde::{Deserialize, Serialize, de::Visitor, ser::SerializeMap};
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Record {
inner: Vec<(String, Value)>,
}
#[repr(transparent)]
pub struct CasedRecord<Sensitivity: CaseSensitivity>(Record, PhantomData<Sensitivity>);
impl<Sensitivity: CaseSensitivity> CasedRecord<Sensitivity> {
#[inline]
const fn from_record(record: &Record) -> &Self {
unsafe { &*(record as *const Record as *const Self) }
}
#[inline]
const fn from_record_mut(record: &mut Record) -> &mut Self {
unsafe { &mut *(record as *mut Record as *mut Self) }
}
pub fn index_of(&self, col: impl AsRef<str>) -> Option<usize> {
let col = col.as_ref();
self.0.columns().rposition(|k| Sensitivity::eq(k, col))
}
pub fn contains(&self, col: impl AsRef<str>) -> bool {
self.index_of(col.as_ref()).is_some()
}
pub fn get(&self, col: impl AsRef<str>) -> Option<&Value> {
let index = self.index_of(col.as_ref())?;
Some(self.0.get_index(index)?.1)
}
pub fn get_mut(&mut self, col: impl AsRef<str>) -> Option<&mut Value> {
let index = self.index_of(col.as_ref())?;
Some(self.0.get_index_mut(index)?.1)
}
pub fn remove(&mut self, col: impl AsRef<str>) -> Option<Value> {
let index = self.index_of(col.as_ref())?;
Some(self.0.remove_index(index))
}
pub fn insert<K>(&mut self, col: K, val: Value) -> Option<Value>
where
K: AsRef<str> + Into<String>,
{
if let Some(curr_val) = self.get_mut(col.as_ref()) {
Some(std::mem::replace(curr_val, val))
} else {
self.0.push(col, val);
None
}
}
}
impl<'a> WrapCased for &'a Record {
type Wrapper<S: CaseSensitivity> = &'a CasedRecord<S>;
#[inline]
fn case_sensitive(self) -> Self::Wrapper<CaseSensitive> {
CasedRecord::<CaseSensitive>::from_record(self)
}
#[inline]
fn case_insensitive(self) -> Self::Wrapper<CaseInsensitive> {
CasedRecord::<CaseInsensitive>::from_record(self)
}
}
impl<'a> WrapCased for &'a mut Record {
type Wrapper<S: CaseSensitivity> = &'a mut CasedRecord<S>;
#[inline]
fn case_sensitive(self) -> Self::Wrapper<CaseSensitive> {
CasedRecord::<CaseSensitive>::from_record_mut(self)
}
#[inline]
fn case_insensitive(self) -> Self::Wrapper<CaseInsensitive> {
CasedRecord::<CaseInsensitive>::from_record_mut(self)
}
}
impl AsRef<Record> for Record {
fn as_ref(&self) -> &Record {
self
}
}
impl AsMut<Record> for Record {
fn as_mut(&mut self) -> &mut Record {
self
}
}
impl Deref for Record {
type Target = CasedRecord<CaseSensitive>;
fn deref(&self) -> &Self::Target {
self.case_sensitive()
}
}
impl DerefMut for Record {
fn deref_mut(&mut self) -> &mut Self::Target {
self.case_sensitive()
}
}
pub struct DynCasedRecord<R> {
record: R,
casing: Casing,
}
impl Clone for DynCasedRecord<&Record> {
fn clone(&self) -> Self {
*self
}
}
impl Copy for DynCasedRecord<&Record> {}
impl<'a> DynCasedRecord<&'a Record> {
pub fn index_of(self, col: impl AsRef<str>) -> Option<usize> {
match self.casing {
Casing::Sensitive => self.record.case_sensitive().index_of(col.as_ref()),
Casing::Insensitive => self.record.case_insensitive().index_of(col.as_ref()),
}
}
pub fn contains(self, col: impl AsRef<str>) -> bool {
self.get(col.as_ref()).is_some()
}
pub fn get(self, col: impl AsRef<str>) -> Option<&'a Value> {
match self.casing {
Casing::Sensitive => self.record.case_sensitive().get(col.as_ref()),
Casing::Insensitive => self.record.case_insensitive().get(col.as_ref()),
}
}
}
impl<'a> DynCasedRecord<&'a mut Record> {
pub fn reborrow(&self) -> DynCasedRecord<&Record> {
DynCasedRecord {
record: &*self.record,
casing: self.casing,
}
}
pub fn reborrow_mut(&mut self) -> DynCasedRecord<&mut Record> {
DynCasedRecord {
record: &mut *self.record,
casing: self.casing,
}
}
pub fn get_mut(self, col: impl AsRef<str>) -> Option<&'a mut Value> {
match self.casing {
Casing::Sensitive => self.record.case_sensitive().get_mut(col.as_ref()),
Casing::Insensitive => self.record.case_insensitive().get_mut(col.as_ref()),
}
}
pub fn remove(self, col: impl AsRef<str>) -> Option<Value> {
match self.casing {
Casing::Sensitive => self.record.case_sensitive().remove(col.as_ref()),
Casing::Insensitive => self.record.case_insensitive().remove(col.as_ref()),
}
}
pub fn insert<K>(self, col: K, val: Value) -> Option<Value>
where
K: AsRef<str> + Into<String>,
{
match self.casing {
Casing::Sensitive => self.record.case_sensitive().insert(col.as_ref(), val),
Casing::Insensitive => self.record.case_insensitive().insert(col.as_ref(), val),
}
}
}
impl Record {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: Vec::with_capacity(capacity),
}
}
pub fn memory_size(&self) -> usize {
std::mem::size_of::<Self>()
+ self
.inner
.iter()
.map(|(k, v)| k.capacity() + v.memory_size())
.sum::<usize>()
}
pub fn cased(&self, casing: Casing) -> DynCasedRecord<&Record> {
DynCasedRecord {
record: self,
casing,
}
}
pub fn cased_mut(&mut self, casing: Casing) -> DynCasedRecord<&mut Record> {
DynCasedRecord {
record: self,
casing,
}
}
pub fn from_raw_cols_vals(
cols: Vec<String>,
vals: Vec<Value>,
input_span: Span,
creation_site_span: Span,
) -> Result<Self, ShellError> {
if cols.len() == vals.len() {
let inner = cols.into_iter().zip(vals).collect();
Ok(Self { inner })
} else {
Err(ShellError::RecordColsValsMismatch {
bad_value: input_span,
creation_site: creation_site_span,
})
}
}
pub fn iter(&self) -> Iter<'_> {
self.into_iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_> {
self.into_iter()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn push(&mut self, col: impl Into<String>, val: Value) {
self.inner.push((col.into(), val));
}
pub fn get_index(&self, idx: usize) -> Option<(&String, &Value)> {
self.inner.get(idx).map(|(col, val): &(_, _)| (col, val))
}
pub fn get_index_mut(&mut self, idx: usize) -> Option<(&mut String, &mut Value)> {
self.inner.get_mut(idx).map(|(col, val)| (col, val))
}
fn remove_index(&mut self, index: usize) -> Value {
self.inner.remove(index).1
}
pub fn retain<F>(&mut self, mut keep: F)
where
F: FnMut(&str, &Value) -> bool,
{
self.retain_mut(|k, v| keep(k, v));
}
pub fn retain_mut<F>(&mut self, mut keep: F)
where
F: FnMut(&str, &mut Value) -> bool,
{
self.inner.retain_mut(|(col, val)| keep(col, val));
}
pub fn truncate(&mut self, len: usize) {
self.inner.truncate(len);
}
pub fn truncate_front(&mut self, len: usize) {
if self.len() < len {
return;
}
let drop = self.len() - len;
self.inner.drain(..drop);
}
pub fn columns(&self) -> Columns<'_> {
Columns {
iter: self.inner.iter(),
}
}
pub fn into_columns(self) -> IntoColumns {
IntoColumns {
iter: self.inner.into_iter(),
}
}
pub fn values(&self) -> Values<'_> {
Values {
iter: self.inner.iter(),
}
}
pub fn into_values(self) -> IntoValues {
IntoValues {
iter: self.inner.into_iter(),
}
}
pub fn drain<R>(&mut self, range: R) -> Drain<'_>
where
R: RangeBounds<usize> + Clone,
{
Drain {
iter: self.inner.drain(range),
}
}
pub fn sort_cols(&mut self) {
self.inner.sort_by(|(k1, _), (k2, _)| k1.cmp(k2))
}
}
impl Serialize for Record {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut map = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self {
map.serialize_entry(k, v)?;
}
map.end()
}
}
impl<'de> Deserialize<'de> for Record {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(RecordVisitor)
}
}
struct RecordVisitor;
impl<'de> Visitor<'de> for RecordVisitor {
type Value = Record;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a nushell `Record` mapping string keys/columns to nushell `Value`")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut record = Record::with_capacity(map.size_hint().unwrap_or(0));
while let Some((key, value)) = map.next_entry::<String, Value>()? {
if record.insert(key, value).is_some() {
return Err(serde::de::Error::custom(
"invalid entry, duplicate keys are not allowed for `Record`",
));
}
}
Ok(record)
}
}
impl FromIterator<(String, Value)> for Record {
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
Self {
inner: iter.into_iter().collect(),
}
}
}
impl Extend<(String, Value)> for Record {
fn extend<T: IntoIterator<Item = (String, Value)>>(&mut self, iter: T) {
for (k, v) in iter {
self.push(k, v)
}
}
}
pub struct IntoIter {
iter: std::vec::IntoIter<(String, Value)>,
}
impl Iterator for IntoIter {
type Item = (String, Value);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for IntoIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl ExactSizeIterator for IntoIter {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for IntoIter {}
impl IntoIterator for Record {
type Item = (String, Value);
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
iter: self.inner.into_iter(),
}
}
}
pub struct Iter<'a> {
iter: std::slice::Iter<'a, (String, Value)>,
}
impl<'a> Iterator for Iter<'a> {
type Item = (&'a String, &'a Value);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(col, val): &(_, _)| (col, val))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for Iter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(col, val): &(_, _)| (col, val))
}
}
impl ExactSizeIterator for Iter<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for Iter<'_> {}
impl<'a> IntoIterator for &'a Record {
type Item = (&'a String, &'a Value);
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter {
iter: self.inner.iter(),
}
}
}
pub struct IterMut<'a> {
iter: std::slice::IterMut<'a, (String, Value)>,
}
impl<'a> Iterator for IterMut<'a> {
type Item = (&'a String, &'a mut Value);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(col, val)| (&*col, val))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for IterMut<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(col, val)| (&*col, val))
}
}
impl ExactSizeIterator for IterMut<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for IterMut<'_> {}
impl<'a> IntoIterator for &'a mut Record {
type Item = (&'a String, &'a mut Value);
type IntoIter = IterMut<'a>;
fn into_iter(self) -> Self::IntoIter {
IterMut {
iter: self.inner.iter_mut(),
}
}
}
pub struct Columns<'a> {
iter: std::slice::Iter<'a, (String, Value)>,
}
impl<'a> Iterator for Columns<'a> {
type Item = &'a String;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(col, _)| col)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for Columns<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(col, _)| col)
}
}
impl ExactSizeIterator for Columns<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for Columns<'_> {}
pub struct IntoColumns {
iter: std::vec::IntoIter<(String, Value)>,
}
impl Iterator for IntoColumns {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(col, _)| col)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for IntoColumns {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(col, _)| col)
}
}
impl ExactSizeIterator for IntoColumns {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for IntoColumns {}
pub struct Values<'a> {
iter: std::slice::Iter<'a, (String, Value)>,
}
impl<'a> Iterator for Values<'a> {
type Item = &'a Value;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(_, val)| val)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for Values<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(_, val)| val)
}
}
impl ExactSizeIterator for Values<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for Values<'_> {}
pub struct IntoValues {
iter: std::vec::IntoIter<(String, Value)>,
}
impl Iterator for IntoValues {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(_, val)| val)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for IntoValues {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(_, val)| val)
}
}
impl ExactSizeIterator for IntoValues {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for IntoValues {}
pub struct Drain<'a> {
iter: std::vec::Drain<'a, (String, Value)>,
}
impl Iterator for Drain<'_> {
type Item = (String, Value);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for Drain<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl ExactSizeIterator for Drain<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for Drain<'_> {}
#[macro_export]
macro_rules! record {
{$($col:expr => $val:expr),+ $(,)?} => {
$crate::Record::from_raw_cols_vals(
::std::vec![$($col.into(),)+],
::std::vec![$($val,)+],
$crate::Span::unknown(),
$crate::Span::unknown(),
).unwrap()
};
{} => {
$crate::Record::new()
};
}
#[macro_export]
macro_rules! test_record {
{$($col:expr => $val:expr),+ $(,)?} => {
$crate::Value::test_record($crate::record! {
$($col => $crate::IntoValue::into_value($val, $crate::Span::test_data())),+
})
};
{} => {
record! {}
};
}