Skip to content

Commit

Permalink
chore(vrl): Add Kind::remove (vectordotdev#14775)
Browse files Browse the repository at this point in the history
  • Loading branch information
fuchsnj authored Oct 20, 2022
1 parent 9225175 commit 78a057f
Show file tree
Hide file tree
Showing 14 changed files with 1,093 additions and 388 deletions.
12 changes: 12 additions & 0 deletions lib/lookup/src/lookup_v2/owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,18 @@ impl<'a> ValuePath<'a> for &'a Vec<OwnedSegment> {
}
}

impl<'a> ValuePath<'a> for &'a [OwnedSegment] {
type Iter = OwnedSegmentSliceIter<'a>;

fn segment_iter(&self) -> Self::Iter {
OwnedSegmentSliceIter {
segments: self,
index: 0,
coalesce_i: 0,
}
}
}

impl<'a> ValuePath<'a> for &'a OwnedValuePath {
type Iter = OwnedSegmentSliceIter<'a>;

Expand Down
1 change: 0 additions & 1 deletion lib/value/src/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ mod crud;
mod debug;

pub mod merge;
pub mod remove;

pub use crud::*;

Expand Down
33 changes: 33 additions & 0 deletions lib/value/src/kind/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@ impl<T: Ord + Clone> Collection<T> {
self.unknown.is_exact()
}

/// Returns an enum describing if the collection is empty.
#[must_use]
pub fn is_empty(&self) -> EmptyState {
if self.known.is_empty() {
if self.unknown_kind().contains_any_defined() {
EmptyState::Maybe
} else {
EmptyState::Always
}
} else {
EmptyState::Never
}
}

/// Set all "unknown" collection elements to the given kind.
pub fn set_unknown(&mut self, unknown: impl Into<Kind>) {
self.unknown = unknown.into().into();
Expand Down Expand Up @@ -266,6 +280,25 @@ impl<T: Ord + Clone> Collection<T> {
}
}

pub trait CollectionRemove {
type Key: Ord;

fn remove_known(&mut self, key: &Self::Key);
}

/// Collections have an "unknown" component, so it can't know in all cases if the value this
/// collection represents is actually empty/not empty, so the state is represented with 3 variants.
#[derive(Debug)]
pub enum EmptyState {
// The collection is guaranteed to be empty.
Always,
// The collection may or may not actually be empty. There is not enough type information to
// determine. (There are unknown fields/indices that may exist, but there are no known values.)
Maybe,
// The collection is guaranteed to NOT be empty.
Never,
}

impl<T: Ord> From<BTreeMap<T, Kind>> for Collection<T> {
fn from(known: BTreeMap<T, Kind>) -> Self {
Self {
Expand Down
11 changes: 11 additions & 0 deletions lib/value/src/kind/collection/field.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use crate::kind::collection::CollectionRemove;
use crate::kind::Collection;

/// A `field` type that can be used in `Collection<Field>`
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Field(lookup::FieldBuf);
Expand All @@ -16,6 +19,14 @@ impl Field {
}
}

impl CollectionRemove for Collection<Field> {
type Key = Field;

fn remove_known(&mut self, key: &Field) {
self.known.remove(key);
}
}

impl std::ops::Deref for Field {
type Target = lookup::FieldBuf;

Expand Down
51 changes: 50 additions & 1 deletion lib/value/src/kind/collection/index.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::kind::collection::CollectionRemove;
use crate::kind::Collection;

/// An `index` type that can be used in `Collection<Index>`
Expand All @@ -22,7 +23,35 @@ impl Collection<Index> {
/// Returns the largest known index, or None if no known indices exist.
#[must_use]
pub fn largest_known_index(&self) -> Option<usize> {
self.known().keys().map(|i| i.to_usize()).max()
self.known()
.iter()
.filter_map(|(i, kind)| {
if kind.contains_any_defined() {
Some(i.to_usize())
} else {
None
}
})
.max()
}

/// Converts a negative index to a positive index (only if the exact positive index is known).
#[must_use]
pub fn get_positive_index(&self, index: isize) -> Option<usize> {
if self.unknown_kind().contains_any_defined() {
// positive index can't be known if there are unknown values
return None;
}

let negative_index = (-index) as usize;
if let Some(largest_known_index) = self.largest_known_index() {
if largest_known_index >= negative_index - 1 {
// The exact index to remove is known.
return Some(((largest_known_index as isize) + 1 + index) as usize);
}
}
// Removing a non-existing index
None
}

/// The minimum possible length an array could be given the type information.
Expand All @@ -41,6 +70,26 @@ impl Collection<Index> {
Some(self.min_length())
}
}

/// Removes the known value at the given index and shifts the
/// elements to the left.
pub fn remove_shift(&mut self, index: usize) {
let min_length = self.min_length();
self.known_mut().remove(&index.into());
for i in index..min_length {
if let Some(value) = self.known_mut().remove(&(index + 1).into()) {
self.known_mut().insert(index.into(), value);
}
}
}
}

impl CollectionRemove for Collection<Index> {
type Key = Index;

fn remove_known(&mut self, key: &Index) {
self.remove_shift(key.0);
}
}

impl From<usize> for Index {
Expand Down
13 changes: 13 additions & 0 deletions lib/value/src/kind/comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,19 @@ impl Kind {
pub const fn contains_object(&self) -> bool {
self.object.is_some() || self.is_never()
}

/// Returns `true` if the type contains _at least_ one non-collection type.
#[must_use]
pub const fn contains_primitive(&self) -> bool {
self.bytes.is_some()
|| self.null.is_some()
|| self.boolean.is_some()
|| self.float.is_some()
|| self.integer.is_some()
|| self.regex.is_some()
|| self.timestamp.is_some()
|| self.undefined.is_some()
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions lib/value/src/kind/crud/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod get;
pub mod insert;
pub mod remove;
Loading

0 comments on commit 78a057f

Please sign in to comment.