Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 85 additions & 14 deletions grovedb-element/src/element/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,16 @@ impl Element {
/// tree's aggregate count when inserted. Sums (if any) still propagate.
///
/// Returns `InvalidInput` if `inner` is already wrapped in any wrapper
/// variant (`NonCounted` or `NotSummed`) — the wrappers are mutually
/// exclusive and may not nest in either direction. Use
/// `into_non_counted` to wrap idempotently when `inner` may already be
/// `NonCounted`; use that helper's `Result` return for the
/// variant (`NonCounted`, `NotSummed`, or `NotCountedOrSummed`) — the
/// wrappers are mutually exclusive and may not nest in either direction.
/// Use `into_non_counted` to wrap idempotently when `inner` may already
/// be `NonCounted`; use that helper's `Result` return for the
/// cross-wrapper case.
pub fn new_non_counted(inner: Element) -> Result<Self, ElementError> {
if matches!(inner, Element::NonCounted(_) | Element::NotSummed(_)) {
if matches!(
inner,
Element::NonCounted(_) | Element::NotSummed(_) | Element::NotCountedOrSummed(_)
) {
return Err(ElementError::InvalidInput(
"NonCounted cannot wrap another wrapper",
));
Expand All @@ -405,15 +408,26 @@ impl Element {
/// Wrap `self` in `NonCounted`. If `self` is already `NonCounted`,
/// returns it unchanged (idempotent on `NonCounted`).
///
/// Returns `InvalidInput` if `self` is `NotSummed` — the two wrappers
/// are mutually exclusive. Callers that need the unconditional wrapping
/// path should ensure the input is a non-wrapper variant before calling.
/// Returns `InvalidInput` if `self` is any other wrapper variant — the
/// wrappers are mutually exclusive. Callers that need the unconditional
/// wrapping path should ensure the input is a non-wrapper variant
/// before calling.
pub fn into_non_counted(self) -> Result<Self, ElementError> {
match self {
Element::NonCounted(_) => Ok(self),
Element::NonCounted(_) => {
// Re-validate the idempotent path: even though only valid
// NonCounted values should reach here via construction, a
// hand-built nested-wrapper value would slip through without
// this check.
self.validate_wrapper_invariants()?;
Ok(self)
}
Element::NotSummed(_) => Err(ElementError::InvalidInput(
"cannot wrap NotSummed in NonCounted; wrappers are mutually exclusive",
)),
Element::NotCountedOrSummed(_) => Err(ElementError::InvalidInput(
"cannot wrap NotCountedOrSummed in NonCounted; wrappers are mutually exclusive",
)),
other => Ok(Element::NonCounted(Box::new(other))),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
Expand All @@ -425,7 +439,8 @@ impl Element {
/// Only the four sum-tree variants are accepted: `SumTree`, `BigSumTree`,
/// `CountSumTree`, `ProvableCountSumTree`. Any other element — including
/// items, sum items, references, non-sum trees, and any wrapper
/// (`NonCounted`, `NotSummed`) — is rejected with `InvalidInput`.
/// (`NonCounted`, `NotSummed`, `NotCountedOrSummed`) — is rejected with
/// `InvalidInput`.
pub fn new_not_summed(inner: Element) -> Result<Self, ElementError> {
match inner {
Element::SumTree(..)
Expand All @@ -442,16 +457,72 @@ impl Element {
/// Wrap `self` in `NotSummed`. If `self` is already `NotSummed`, returns
/// it unchanged (idempotent on `NotSummed`).
///
/// Returns `InvalidInput` if `self` is `NonCounted` (the two wrappers
/// are mutually exclusive) or any non-sum-tree variant. Mirrors
/// [`Element::into_non_counted`].
/// Returns `InvalidInput` if `self` is any other wrapper (the three
/// wrappers are mutually exclusive) or any non-sum-tree variant.
/// Mirrors [`Element::into_non_counted`].
pub fn into_not_summed(self) -> Result<Self, ElementError> {
match self {
Element::NotSummed(_) => Ok(self),
Element::NotSummed(_) => {
// Re-validate the idempotent path; see `into_non_counted`
// for rationale.
self.validate_wrapper_invariants()?;
Ok(self)
}
Element::NonCounted(_) => Err(ElementError::InvalidInput(
"cannot wrap NonCounted in NotSummed; wrappers are mutually exclusive",
)),
Element::NotCountedOrSummed(_) => Err(ElementError::InvalidInput(
"cannot wrap NotCountedOrSummed in NotSummed; wrappers are mutually exclusive",
)),
other => Self::new_not_summed(other),
}
}

/// Wrap a sum-tree variant in `NotCountedOrSummed` so it contributes 0
/// to BOTH its parent's running sum AND its parent's count when
/// inserted.
///
/// Only the four sum-tree variants are accepted: `SumTree`, `BigSumTree`,
/// `CountSumTree`, `ProvableCountSumTree`. Any other element — including
/// items, sum items, references, non-sum trees, and any wrapper
/// (`NonCounted`, `NotSummed`, `NotCountedOrSummed`) — is rejected with
/// `InvalidInput`.
///
/// Note: at insert time the parent must be `CountSumTree` or
/// `ProvableCountSumTree`. The merk-layer insert guard enforces that.
pub fn new_not_counted_or_summed(inner: Element) -> Result<Self, ElementError> {
match inner {
Element::SumTree(..)
| Element::BigSumTree(..)
| Element::CountSumTree(..)
| Element::ProvableCountSumTree(..) => Ok(Element::NotCountedOrSummed(Box::new(inner))),
_ => Err(ElementError::InvalidInput(
"NotCountedOrSummed inner element must be a sum-tree variant (SumTree, \
BigSumTree, CountSumTree, or ProvableCountSumTree)",
)),
}
}

/// Wrap `self` in `NotCountedOrSummed`. If `self` is already
/// `NotCountedOrSummed`, returns it unchanged (idempotent).
///
/// Returns `InvalidInput` if `self` is any other wrapper (the three
/// wrappers are mutually exclusive) or any non-sum-tree variant.
pub fn into_not_counted_or_summed(self) -> Result<Self, ElementError> {
match self {
Element::NotCountedOrSummed(_) => {
// Re-validate the idempotent path; see `into_non_counted`
// for rationale.
self.validate_wrapper_invariants()?;
Ok(self)
}
Element::NonCounted(_) => Err(ElementError::InvalidInput(
"cannot wrap NonCounted in NotCountedOrSummed; wrappers are mutually exclusive",
)),
Element::NotSummed(_) => Err(ElementError::InvalidInput(
"cannot wrap NotSummed in NotCountedOrSummed; wrappers are mutually exclusive",
)),
other => Self::new_not_counted_or_summed(other),
}
}
}
Loading
Loading