pub struct StorePath { /* private fields */ }Expand description
Where a value lives in the store, as the levels it is under.
A path is built from segments and only from segments, so a name is a name:
putting "dark.mode" in one addresses a single value with a dot in it, not
two levels.
Two forms answer the two kinds of engine, and a path holds whichever one it arrived in. A flat engine keeps a key whole and addresses it by the joined spelling; a document engine keeps a level at a time and addresses it by the levels. The other form is built on the first reader that wants it and kept, so a path costs one of the two, and a scan that never asks for the other never pays for it.
Which is not a detail: both directions are taken per key of every scan. Splitting a key allocates for the list of levels; spelling levels out walks them for a separator and an escape and builds a string. Whichever a caller does not read is the whole of that cost.
Implementations§
Source§impl StorePath
impl StorePath
Sourcepub const fn from_static(
segments: &'static [&'static str],
joined: &'static str,
) -> Self
pub const fn from_static( segments: &'static [&'static str], joined: &'static str, ) -> Self
A path whose levels are known when the code is compiled.
Both forms are handed over ready, so this allocates nothing: no level may
be empty, and joined must be exactly the joined spelling a path keeps
for segments, escapes and all.
Both are checked here rather than trusted. The check is a const fn, so
a path written into a const - StateScope::PATH, which is where these
come from - fails to compile when the halves disagree, whether a macro or
a hand-written impl wrote them. A const panic carries no formatting, so
it names the invariant and not the level; the #[amethystate(prefix = ...)] macro checks the same two things first and points at the
attribute.
§Panics
If any level is empty, or if joined is not the joined form of
segments. At compile time when the call is in a const context, which is
the only place it is meant to be.
Sourcepub fn segment(name: impl AsRef<str>) -> Self
pub fn segment(name: impl AsRef<str>) -> Self
One level named name, whatever name contains - the empty name
included.
A level’s name is the caller’s to choose and every document format this
library writes lets a member be named with nothing, so a name that is
empty is a name. It is the joined spelling that cannot carry one alone:
"" reads back as the root, so the one-level path [""] has no
spelling of its own and a flat text document cannot hold it.
Sourcepub fn as_one_level(&self) -> Self
pub fn as_one_level(&self) -> Self
The whole of this path as one level, its spelling being the name.
What a store with no levels is addressed by: ui.theme becomes one
level called ui.theme, and a level of the original holding a . keeps
the escape that tells it from a separator, so the two spell differently
here as well.
§Panics
If this is the root, which spells nothing and so names no level.
Sourcepub fn from_segments<I, S>(segments: I) -> Self
pub fn from_segments<I, S>(segments: I) -> Self
A path out of the levels it is under, outermost first.
No levels at all is the root, and here that is a statement rather than
an accident: an as_root struct’s path is written out as no levels.
A list that came from data and turned out empty is somebody’s filter
rather than somebody’s decision, and goes through
StorePath::try_from_segments, which refuses it.
StorePath::try_from_segments refuses it, because a list that came
from data and turned out empty is not something anyone said.
Sourcepub fn try_from_segments<I, S>(segments: I) -> Result<Self, StorePathError>
pub fn try_from_segments<I, S>(segments: I) -> Result<Self, StorePathError>
StorePath::from_segments for levels that can turn out to be empty.
Which is where the two differ: a written-out empty list means the root,
and a computed one that filtered down to nothing means nobody decided.
The second is refused with StorePathError::EmptyPath, because it
would name the whole store, and a write through it would replace
everything.
Sourcepub fn push(&self, name: impl AsRef<str>) -> Self
pub fn push(&self, name: impl AsRef<str>) -> Self
This path with one more level under it, whatever name contains.
StorePath::push taking a name the caller already holds shared.
What a document engine has: a level’s name is stored as one of these, and a scan puts a path together out of names it is holding anyway. The other form copies the name into a fresh one per key.
Sourcepub fn segments(&self) -> impl ExactSizeIterator<Item = Level<'_>> + '_
pub fn segments(&self) -> impl ExactSizeIterator<Item = Level<'_>> + '_
The levels, outermost first.
Borrowed where the level is a run of the joined form, which is every level whose name carries no separator to escape.
Sourcepub fn segment_at(&self, index: usize) -> Option<Level<'_>>
pub fn segment_at(&self, index: usize) -> Option<Level<'_>>
One level, or None past the end.
Sourcepub fn is_root(&self) -> bool
pub fn is_root(&self) -> bool
Whether this path names the whole store rather than anything in it.
Answered per state rather than through len, because
counting the levels of a joined key walks the whole of it - and that is
the state a flat engine’s keys arrive in, asked once per key of every
scan through level_under.
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
How many levels the path has.
There is deliberately no is_empty beside it. A path of no levels is
the root - the one that names the whole store - and that is a thing
rather than the absence of one, so is_root is what
asks. is_empty would be a second name for the same question, and the
worse of the two.
Sourcepub fn starts_with(&self, prefix: &StorePath) -> bool
pub fn starts_with(&self, prefix: &StorePath) -> bool
Whether every level of prefix starts this path.
Compared level by level, so ui does not start uix.width - which
comparing the joined strings would say it does.
Sourcepub fn strip_prefix(&self, prefix: &StorePath) -> Option<StorePath>
pub fn strip_prefix(&self, prefix: &StorePath) -> Option<StorePath>
The levels below prefix, or None when prefix does not start this
path.
Sourcepub fn overlaps(&self, other: &StorePath) -> bool
pub fn overlaps(&self, other: &StorePath) -> bool
Whether this subtree and other’s hold any key in common.
Two subtrees are nested or apart and never half over each other, so this
is two containment tests and equality needs no arm of its own:
starts_with admits the prefix itself.
Sourcepub fn parent(&self) -> Option<StorePath>
pub fn parent(&self) -> Option<StorePath>
The path one level up, or None at the root.
Shares the level list rather than copying it short: walking up is asked for one ancestor after another, and each answer used to be the whole list copied to drop the end of it.
Sourcepub fn upwards(&self) -> impl Iterator<Item = StorePath> + '_
pub fn upwards(&self) -> impl Iterator<Item = StorePath> + '_
This path and every path it sits under, nearest first, the root last.
The set a place that holds this one can be at: a path is held at itself or at one of its ancestors, and nowhere else. Walking it costs one level list, made once and shared by every step - where asking for a parent and then its parent used to copy the list per step, and throw each copy away after a comparison.
Sourcepub fn level_under(&self, prefix: &StorePath) -> Under<'_>
pub fn level_under(&self, prefix: &StorePath) -> Under<'_>
Where this path sits under prefix, and the level it sits at.
The method level_under would be if it had nothing to check. That
one takes a key an engine read off a disk and can refuse it; a path has
already been through that, so this only reads.
Which is what lets the rest of the library ask the question without holding a key: an entry one level down and one two levels down are different answers, and telling them apart is a map’s whole business.
Sourcepub fn name_under(&self, prefix: &StorePath) -> Option<Level<'_>>
pub fn name_under(&self, prefix: &StorePath) -> Option<Level<'_>>
The level that follows prefix, read straight off the joined form.
The same answer as starts_with(prefix) followed by
segment_at(prefix.len()), reached without splitting either path into
levels. That matters where it is used: a scan hands back a path per
stored key, and the caller wants one name from each, so splitting every
key into a level per allocation is work thrown away as soon as it is
done.
Borrowed unless the name carries an escaped separator, which is the only case where the level is not a run of the joined string.
Sourcepub fn entry_name<'k>(&self, key: &'k StorePath) -> Option<Level<'k>>
pub fn entry_name<'k>(&self, key: &'k StorePath) -> Option<Level<'k>>
The name key is stored under, below this path: the last level of
what remains, where StorePath::name_under is the first.
Taking a prefix off does not touch the end, so the last level of what
remains is the last level of key - there is no remainder to build, and
the name is borrowed out of key rather than copied out of it.
Sourcepub fn parse_joined(joined: &str) -> Result<Self, StorePathError>
pub fn parse_joined(joined: &str) -> Result<Self, StorePathError>
Reads a joined spelling back into the path it spells.
Only for data already on disk: a path in code is built from its segments, so nothing else needs to parse one. Fallible because a key this library did not write can hold a level with no name, and such a path is not one.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for StorePath
Read back through StorePath::parse_joined, so the invariants are checked
where the document is read rather than wherever somebody first asks for a
level: a key with a nameless level or a dangling escape is refused here and
cannot reach anything that would have to answer for it later.
impl<'de> Deserialize<'de> for StorePath
Read back through StorePath::parse_joined, so the invariants are checked
where the document is read rather than wherever somebody first asks for a
level: a key with a nameless level or a dangling escape is refused here and
cannot reach anything that would have to answer for it later.
Source§fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
Source§impl Display for StorePath
The joined spelling, written a level at a time rather than built and then
written: printing a path is not a reason to make one hold a second form of
itself.
impl Display for StorePath
The joined spelling, written a level at a time rather than built and then written: printing a path is not a reason to make one hold a second form of itself.
impl Eq for StorePath
Source§impl<'a> From<&'a StorePath> for PathRef<'a>
Borrowing a path costs nothing and checks nothing: it has been through the
check already.
impl<'a> From<&'a StorePath> for PathRef<'a>
Borrowing a path costs nothing and checks nothing: it has been through the check already.
Source§impl From<StaticPath> for StorePath
impl From<StaticPath> for StorePath
Source§fn from(at: StaticPath) -> Self
fn from(at: StaticPath) -> Self
Source§impl Hash for StorePath
By the levels, so it agrees with Eq however the path arrived.
impl Hash for StorePath
By the levels, so it agrees with Eq however the path arrived.
str’s own Hash ends what it writes, so two levels cannot run together
into the hash of one - ["a", "b"] and ["ab"] are different paths and
hash differently.
Source§impl IntoStorePath for StorePath
impl IntoStorePath for StorePath
fn into_store_path(self) -> Result<StorePath, StorePathError>
Source§impl IntoStorePath for &StorePath
impl IntoStorePath for &StorePath
fn into_store_path(self) -> Result<StorePath, StorePathError>
Source§impl MapEntryPath for StorePath
impl MapEntryPath for StorePath
Source§impl Ord for StorePath
The order a store lists in: by the levels, outermost first.
impl Ord for StorePath
The order a store lists in: by the levels, outermost first.
The flat engines range over Key, whose byte order is this order, so
anything sorting paths for itself agrees with them by construction.
Not by the joined spelling. Joining puts a separator between levels and
escapes it inside them, and a name holding a byte below that separator then
sorts on the wrong side of a boundary: ["a!"] comes after ["a", "b"] by
levels and before it by spelling. The levels are what a path is, and
Key encodes them so that a flat engine’s byte order says the same thing.
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialEq for StorePath
Equal paths are the ones that address the same place, which is the ones
holding the same levels - the same question Ord answers, asked of the
same form, so the two cannot drift apart.
impl PartialEq for StorePath
Equal paths are the ones that address the same place, which is the ones
holding the same levels - the same question Ord answers, asked of the
same form, so the two cannot drift apart.