Skip to main content

Limits

Struct Limits 

Source
pub struct Limits { /* private fields */ }
Expand description

Resource limits: secondary safeguards against resource exhaustion.

Because parsing is iterative and O(n), no limit is needed for safety; these bound memory and time on hostile input. Every limit that is exceeded yields a limit diagnostic (Y2xxx) whose help names the setting to raise, e.g. raise Limits::max_depth (currently 128).

Three profiles:

LimitLimits::default()Limits::untrusted()Limits::unlimited()
max_depth1,024128none
alias_budgetmax(10 × own nodes, 1,000,000)max(2 × own nodes, 100,000)none
alias_byte_budgetmax(10 × input bytes, 64 MiB)max(2 × input bytes, 8 MiB)none
max_document_size256 MiB16 MiBnone
max_scalar_len64 MiB1 MiBnone
max_documentsnone1,000none
max_typed_depth12864none
max_diagnostics100,0001,000none

The alias budgets bound what Value and serde reads materialise by expanding aliases (nodes, and bytes beyond the input; see Limits::alias_byte_budget). They are counted per document and incrementally from the document’s start, so a read of one node never refuses what the whole document’s read accepts. Each document of a stream has its own budgets: reading a whole stream expands at most the sum of its documents’ budgets, so at most max_documents × the largest one (with untrusted() and small documents: 1,000 × 100,000 nodes and 1,000 × 8 MiB). An alias whose whole expansion would exceed a budget is refused before any of it is replayed, so a refused read costs about the input it read.

A numeric limit of usize::MAX means “no limit”. Use Limits::untrusted() for servers, webhooks, and APIs that parse input from untrusted sources.

Limits::unlimited() removes every bound, and it is the only way to disable the alias budgets (nodes and bytes; alias_budget(usize::MAX) and alias_byte_budget(usize::MAX) make them unreachable instead). Use it only for input you trust completely.

Compatibility presets never change limits: safety is not a compat behaviour.

§Examples

use oneyaml_core::Limits;

// A service reading small uploads: the untrusted profile, tightened.
let l = Limits::untrusted()
    .max_depth(32)
    .max_typed_depth(32)
    .max_document_size(64 * 1024)
    .max_scalar_len(4 * 1024)
    .max_documents(1)
    .max_diagnostics(10)
    .alias_budget(1_000)
    .alias_byte_budget(256 * 1024);
assert_eq!(l.get_max_depth(), 32);
assert_eq!(l.get_max_typed_depth(), 32);
assert_eq!(l.get_max_document_size(), 64 * 1024);
assert_eq!(l.get_max_scalar_len(), 4 * 1024);
assert_eq!(l.get_max_documents(), 1);
assert_eq!(l.get_max_diagnostics(), 10);
// A fixed budget ignores the document's size ...
assert_eq!(l.get_alias_budget(1_000_000), Some(1_000));
assert_eq!(l.get_alias_byte_budget(1 << 30), Some(256 * 1024));
// ... a ratio scales with it, above a floor.
let r = l.alias_budget_ratio(3, 100).alias_byte_budget_ratio(2, 4096);
assert_eq!(r.get_alias_budget(10), Some(100));
assert_eq!(r.get_alias_budget(1_000), Some(3_000));
assert_eq!(r.get_alias_byte_budget(10_000), Some(20_000));
// `unlimited()` is the only profile without alias budgets.
assert_eq!(Limits::unlimited().get_alias_budget(1), None);
assert_eq!(Limits::unlimited().get_alias_byte_budget(1), None);

Implementations§

Source§

impl Limits

Source

pub const fn new() -> Limits

The default profile. Same as Limits::default(), usable in const.

Source

pub const fn untrusted() -> Limits

The profile for untrusted input.

Source

pub const fn unlimited() -> Limits

No limits at all, including no alias budget. Only for trusted input.

Source

pub const fn max_depth(self, depth: usize) -> Limits

Maximum nesting depth of collections, counting block and flow collections together; a top-level collection has depth 1.

Consumed by the parser now; the tree builder, Value/serde, and the emitter will enforce it too.

Source

pub const fn alias_budget(self, nodes: usize) -> Limits

A fixed alias budget: at most nodes nodes may be produced by alias expansion (including merge keys through aliases).

Applies to Value and serde only, never to Document.

Source

pub const fn alias_budget_ratio(self, factor: usize, floor: usize) -> Limits

A ratio alias budget: max(factor × own nodes, floor), where “own nodes” is the number of nodes the document itself contains.

Applies to Value and serde only, never to Document.

Source

pub const fn alias_byte_budget(self, bytes: usize) -> Limits

A fixed alias byte budget: at most bytes bytes may be materialised by alias expansion beyond the input.

Counted per document, incrementally, by Value and serde reads only (never by Document, which expands nothing):

  • every scalar value, key, and tag that alias expansion copies (merge keys through aliases included), in full;
  • each tag use’s %TAG prefix, which a tag shares rather than copies but which its logical text (and so any output of it) repeats;
  • the text of a %TAG tag joined into an enum variant name that names no variant of the target (#[serde(other)], hand-written visitors).

Exceeding it is Y2009 (code::ALIAS_BYTE_BUDGET_EXCEEDED). Independent of Limits::alias_budget, which counts nodes.

Source

pub const fn alias_byte_budget_ratio( self, factor: usize, floor: usize, ) -> Limits

A ratio alias byte budget: max(factor × input bytes, floor), where “input bytes” is how much of the document (from its start, --- or its first content) has been read at the point of the charge, so a read of one node has the budget the whole read has at the same place. See Limits::alias_byte_budget for what is charged.

Source

pub const fn max_document_size(self, bytes: usize) -> Limits

Maximum input size in bytes (the whole stream, after decoding to UTF-8).

Consumed by the parser now; readers will also check it before reading.

Source

pub const fn max_scalar_len(self, bytes: usize) -> Limits

Maximum length in bytes of one scalar’s value (after escapes and folding). Consumed by the parser.

Source

pub const fn max_documents(self, documents: usize) -> Limits

Maximum number of documents in one stream. Consumed by the parser.

Source

pub const fn max_typed_depth(self, depth: usize) -> Limits

Maximum nesting of collections that serde visits through the target type’s own Deserialize impls, i.e. how deep a recursive user type such as struct Tree(Vec<Tree>) may follow the input.

serde’s visitor model recurses once per such level, so this bounds the native stack: measured at about 1.9 KiB per level in release builds and 7.4 KiB in debug builds (examples/stack_probe.rs in oneyaml; the cost depends on the target type). The defaults (128; 64 untrusted) fit a 2 MiB thread stack in both. Before raising it, make sure the deserializing thread’s stack holds max_typed_depth × the per-level cost, e.g. run on a thread built with std::thread::Builder::stack_size; Limits::unlimited() removes the bound entirely, so only use it with non-recursive targets or input you trust. Value targets (and Value fields) are built iteratively and are bounded only by max_depth.

Source

pub const fn max_diagnostics(self, diagnostics: usize) -> Limits

Maximum number of diagnostics (errors and warnings together) one parse or read keeps.

The budget is per stream, shared by errors and warnings, and counts every kind (decoding, settings, syntax, meaning). A list of diagnostics keeps its first max_diagnostics entries in the order it reports them; when more were found, it also keeps the first error (whatever its place: it is the one a strict parse fails with) and then ends with one summary warning, Y2010 (code::DIAGNOSTICS_SUPPRESSED): “N more diagnostics suppressed”, located where the first suppressed one was, whose help names this setting. The summary does not count toward the limit (a capped list holds at most max_diagnostics + 2 entries) and N is exact. Exceeding the limit is never an error by itself: strict parses still fail exactly at the first error, and only then.

Meaning never depends on it: what a read accepts or refuses, has_errors, restricted mode, which edits are accepted, and a read’s cost are the same under every limit. Past it, the syntax tree keeps a diagnostic as a 32-byte skeleton (code, severity, spans) without its texts, and an error reported from there has its code’s summary for a message. Paths that discard warnings build at most 16.

Source

pub const fn get_max_diagnostics(&self) -> usize

The max_diagnostics limit (usize::MAX: none).

Source

pub const fn get_max_typed_depth(&self) -> usize

The max_typed_depth limit (usize::MAX: none).

Source

pub const fn get_max_depth(&self) -> usize

The max_depth limit (usize::MAX: none).

Source

pub const fn get_alias_budget(&self, own_nodes: usize) -> Option<usize>

The alias budget for a document with own_nodes nodes, or None when the budget is disabled (Limits::unlimited()).

Source

pub const fn get_alias_byte_budget(&self, input_bytes: usize) -> Option<usize>

The alias byte budget after input_bytes bytes of the document, or None when it is disabled (Limits::unlimited()).

Source

pub const fn get_max_document_size(&self) -> usize

The max_document_size limit in bytes (usize::MAX: none).

Source

pub const fn get_max_scalar_len(&self) -> usize

The max_scalar_len limit in bytes (usize::MAX: none).

Source

pub const fn get_max_documents(&self) -> usize

The max_documents limit (usize::MAX: none).

Trait Implementations§

Source§

impl Clone for Limits

Source§

fn clone(&self) -> Limits

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Limits

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for Limits

Source§

fn default() -> Limits

Returns the “default value” for a type. Read more
Source§

impl Eq for Limits

Source§

impl Hash for Limits

Source§

fn hash<__H>(&self, state: &mut __H)
where __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Limits

Source§

fn eq(&self, other: &Limits) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Limits

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.