pub struct StateStore { /* private fields */ }Expand description
SQLite state store with an in-memory hot cache.
Hot path: StateStore::lookup_credential reads the cache under an RwLock read
and performs ZERO SQLite work after warmup (provable via
disk_reads). Cold paths (writes, quota,
list) take the connection mutex; see the module docs for the
threading model.
Implementations§
Source§impl StateStore
impl StateStore
Sourcepub fn open(path: &Path) -> Result<Self, StoreError>
pub fn open(path: &Path) -> Result<Self, StoreError>
Open (or create) a store at path, applying pending migrations.
§Backup before migrate (DW-115)
If the database’s schema version is behind this build, a consistent
snapshot is taken via VACUUM INTO to
<path>.bak-<old-version>-<unix-seconds>-<millis> (millisecond
component disambiguates same-second migrations) BEFORE any
migration runs. Failure to create the backup ABORTS the open: no migration
proceeds without a safety copy. (A brand-new, empty database and
in-memory stores skip this — there is no data to lose.)
§Refusal rules
A database whose user_version is NEWER than this build supports
is refused with a clear error (downgrade attempts; the migration
set is forward-only — see crate::state::migrations for the rebuild
path).
§Permissions
On unix the database file is tightened to mode 0600 after create: it stores credential hashes/selectors, so group/other read access granted by the process umask default (0644) is removed. Existing files are also tightened; a failure to set permissions is a hard error rather than silently shipping a world-readable secrets file.
Sourcepub fn open_in_memory() -> Result<Self, StoreError>
pub fn open_in_memory() -> Result<Self, StoreError>
Open an in-memory store (tests and tooling).
Sourcepub fn schema_version(&self) -> Result<u32, StoreError>
pub fn schema_version(&self) -> Result<u32, StoreError>
Current schema version of the open database (PRAGMA user_version).
After Self::open this always equals
crate::state::migrations::LATEST_SCHEMA_VERSION.
Sourcepub fn schema_info(&self) -> Result<SchemaInfo, StoreError>
pub fn schema_info(&self) -> Result<SchemaInfo, StoreError>
Current-vs-latest schema info. Seam for the admin API (DW-022):
current is read live, latest is what this build can migrate to.
Sourcepub fn disk_reads(&self) -> u64
pub fn disk_reads(&self) -> u64
Number of disk (SQLite) reads performed by cache-miss lookups. Test/ops observability for the “no disk on the hot path” contract.
Sourcepub fn cache_hits(&self) -> u64
pub fn cache_hits(&self) -> u64
Number of cache hits served without touching SQLite.
Sourcepub fn upsert_consumer(
&self,
name: &str,
priority: Option<u8>,
groups: &[String],
) -> Result<ConsumerRecord, StoreError>
pub fn upsert_consumer( &self, name: &str, priority: Option<u8>, groups: &[String], ) -> Result<ConsumerRecord, StoreError>
Insert or update a consumer by name; returns the resulting record.
Updating preserves the row id and creation time; priority and
groups change (#124). The consumer cache entry is refreshed.
Sourcepub fn list_consumers(&self) -> Result<Vec<ConsumerRecord>, StoreError>
pub fn list_consumers(&self) -> Result<Vec<ConsumerRecord>, StoreError>
List all consumers (disk read; cold path).
Sourcepub fn add_credential(
&self,
consumer_id: i64,
kind: CredentialKind,
hash: String,
salt: Option<String>,
selector: String,
) -> Result<CredentialRecord, StoreError>
pub fn add_credential( &self, consumer_id: i64, kind: CredentialKind, hash: String, salt: Option<String>, selector: String, ) -> Result<CredentialRecord, StoreError>
Add a credential with a PRE-HASHED value. The store never sees plaintext secrets: hashing and selector derivation are the authenticator’s job (DW-019). The selector’s cache entry is invalidated so the next lookup reflects the new credential.
Sourcepub fn add_credential_from_reference(
&self,
consumer_id: i64,
kind: CredentialKind,
hash: String,
selector: String,
source_ref: &str,
) -> Result<CredentialRecord, StoreError>
pub fn add_credential_from_reference( &self, consumer_id: i64, kind: CredentialKind, hash: String, selector: String, source_ref: &str, ) -> Result<CredentialRecord, StoreError>
Self::add_credential for a config credential seeded from a
${...} REFERENCE (DW-045, #46): records the reference text in
credentials.source_ref (schema v4) — the linkage
Self::revoke_credentials_by_source uses to retire THIS row
when a later seed of the same reference can no longer resolve
it. The reference text is config, not secret bytes (the
resolved value is hashed before it ever reaches the store).
Sourcepub fn revoke_credential(&self, credential_id: i64) -> Result<bool, StoreError>
pub fn revoke_credential(&self, credential_id: i64) -> Result<bool, StoreError>
Revoke a credential by id; returns whether a row was revoked. Idempotent (revoking a revoked credential returns false). The selector’s cache entry is invalidated so the next lookup reflects the revocation.
Sourcepub fn retire_credential(
&self,
credential_id: i64,
at_epoch_secs: i64,
) -> Result<bool, StoreError>
pub fn retire_credential( &self, credential_id: i64, at_epoch_secs: i64, ) -> Result<bool, StoreError>
Schedule a credential’s RETIREMENT (DW-046): the row keeps
authenticating until at_epoch_secs, then stops — the
dual-validity window of key rotation. at in the past or now is
an immediate retirement (equivalent to revocation for lookup
purposes, but recorded as a scheduled stop, not an operator
revocation). Returns whether an active row was updated.
Idempotent: re-retiring moves an existing future retirement
EARLIER only (never later — a scheduled stop cannot be
postponed through this call; issue a new credential instead).
Sourcepub fn list_credentials_for_consumer(
&self,
consumer_name: &str,
) -> Result<Vec<CredentialRecord>, StoreError>
pub fn list_credentials_for_consumer( &self, consumer_name: &str, ) -> Result<Vec<CredentialRecord>, StoreError>
Every credential row of a named consumer (including revoked and retired ones), newest first — the admin rotation surface’s list view. Secret material (hash/salt/selector) never leaves this module; the admin layer projects only the safe fields.
Sourcepub fn revoke_credentials_by_source(
&self,
consumer_id: i64,
kind: CredentialKind,
source_ref: &str,
) -> Result<u64, StoreError>
pub fn revoke_credentials_by_source( &self, consumer_id: i64, kind: CredentialKind, source_ref: &str, ) -> Result<u64, StoreError>
Revoke every ACTIVE credential of consumer_id/kind seeded
from the config reference source_ref (#46): the seed path’s
fail-closed skip — a re-seed whose reference no longer resolves
— calls this so the row a PREVIOUS generation of the same
reference seeded stops authenticating through
CredentialRegistry::Store (the store-backed twin of the
config-registry build, which simply does not install the
credential). Uses the store’s own revocation semantics
(revoked_at, per-selector cache invalidation), so a re-seed
after the source heals inserts a fresh row — revocation never
blocks config re-seeding. Rows WITHOUT the linkage (pre-v4
databases, inline keys, operator-managed rows) are untouched:
they keep the documented upsert-only posture. Returns the number
of rows revoked.
Sourcepub fn rehash_credential(
&self,
credential_id: i64,
selector: &str,
hash: &str,
) -> Result<(), StoreError>
pub fn rehash_credential( &self, credential_id: i64, selector: &str, hash: &str, ) -> Result<(), StoreError>
Replace a credential’s stored hash in place (#124 pepper
transition): used by the authenticator after a SUCCESSFUL legacy
(sha256:) verification when a pepper is configured, upgrading
the row to hmac-sha256:<hex> so the transition completes lazily
— no credential re-issue, and the next lookup of the same
selector serves the peppered hash. The UPDATE is guarded by BOTH
the row id and the selector the credential was looked up under,
so a row rebound to a different selector between the lookup and
this write is left alone instead of being re-hashed. The
selector’s cache entry is invalidated; nothing else about the row
(kind, revocation, timestamps) changes.
Sourcepub fn lookup_credentials_by_selector(
&self,
selector: &str,
) -> Result<Vec<CredentialRecord>, StoreError>
pub fn lookup_credentials_by_selector( &self, selector: &str, ) -> Result<Vec<CredentialRecord>, StoreError>
Disk lookup: all ACTIVE credentials for a selector (revoked rows are ignored). Cold path; feeds the cache.
Sourcepub fn lookup_credential(
&self,
selector: &str,
) -> Result<Option<Arc<Vec<Arc<CredentialRecord>>>>, StoreError>
pub fn lookup_credential( &self, selector: &str, ) -> Result<Option<Arc<Vec<Arc<CredentialRecord>>>>, StoreError>
HOT PATH: look up the active credentials for a selector. Cache hit
performs ZERO SQLite work (an RwLock read and an Arc clone).
Miss reads disk once and fills the cache, including a cached
NEGATIVE result (empty list) for unknown selectors.
Sourcepub fn lookup_consumer(
&self,
name: &str,
) -> Result<Option<Arc<ConsumerRecord>>, StoreError>
pub fn lookup_consumer( &self, name: &str, ) -> Result<Option<Arc<ConsumerRecord>>, StoreError>
Consumer lookup by name. Cached on hit (same counter rules as
Self::lookup_credential); unlike credentials there is no negative
caching — consumer-by-name lookups are a control-plane path, so an
unknown name re-reads disk.
Sourcepub fn delete_legacy_config_placeholder_credentials(
&self,
) -> Result<u64, StoreError>
pub fn delete_legacy_config_placeholder_credentials( &self, ) -> Result<u64, StoreError>
Legacy-cleanup rule (DW-019 review): databases seeded by the
pre-DW-019 build hold api_key rows whose SELECTOR is the plaintext
config key and whose hash is the placeholder
config:api_key:<key> — both embed the secret verbatim, and
without this cleanup they would sit in the store forever (the
post-DW-019 seeding writes a sha256 selector/hash and never
matches them, so the idempotence check skips them). This build
never writes that format, so every matching row is transitional
and is deleted here. A schema migration is overkill for one
build’s placeholder rows: a code-level cleanup at sync time is
sufficient, runs everywhere sync runs (deployments with or
without a state DB), and needs no version bump. JWT/mTLS binding
rows (config:jwt: / config:mtls:) are NOT deleted — those are
the current, non-secret binding-marker format. Returns the number
of rows deleted (0 on a clean or fresh database).
Sourcepub fn invalidate(&self, selector: &str)
pub fn invalidate(&self, selector: &str)
Invalidate one selector’s cache entry (next lookup re-reads disk).
Sourcepub fn invalidate_all(&self)
pub fn invalidate_all(&self)
Invalidate every cache entry (next lookup of anything re-reads disk).
Sourcepub fn incr_quota(
&self,
consumer_id: i64,
counter_key: &str,
window_start: i64,
amount: u64,
limit: Option<u64>,
) -> Result<u64, StoreError>
pub fn incr_quota( &self, consumer_id: i64, counter_key: &str, window_start: i64, amount: u64, limit: Option<u64>, ) -> Result<u64, StoreError>
Atomically add amount to a quota counter, refusing the increment
(writing nothing) when it would exceed limit. Returns the
used-after value. Window semantics are caller-driven: a new
window_start is a NEW counter (rollover = call with the next
window’s start).
Sourcepub fn get_quota(
&self,
consumer_id: i64,
counter_key: &str,
window_start: i64,
) -> Result<u64, StoreError>
pub fn get_quota( &self, consumer_id: i64, counter_key: &str, window_start: i64, ) -> Result<u64, StoreError>
Read the current usage of a quota counter (0 when absent).
Sourcepub fn set_prompt_override(
&self,
prompt_name: &str,
version: &str,
) -> Result<(), StoreError>
pub fn set_prompt_override( &self, prompt_name: &str, version: &str, ) -> Result<(), StoreError>
Set (or replace) the active-version override for a prompt (DW-086). Idempotent: re-setting the same prompt moves the override to the new version. The caller validates that the prompt name and version exist in the CURRENT config before calling (the store does not know the config).
Sourcepub fn clear_prompt_override(&self, prompt_name: &str) -> Result<(), StoreError>
pub fn clear_prompt_override(&self, prompt_name: &str) -> Result<(), StoreError>
Clear the active-version override for a prompt (DW-086):
revert to the config-declared active version. Idempotent
(clearing a prompt with no override is a no-op).
Sourcepub fn get_prompt_override(
&self,
prompt_name: &str,
) -> Result<Option<String>, StoreError>
pub fn get_prompt_override( &self, prompt_name: &str, ) -> Result<Option<String>, StoreError>
Read the active-version override for a prompt (DW-086):
Some(version) when an override exists, None when the
config-declared active version governs.
Sourcepub fn list_prompt_overrides(&self) -> Result<Vec<(String, String)>, StoreError>
pub fn list_prompt_overrides(&self) -> Result<Vec<(String, String)>, StoreError>
Every prompt override row (prompt_name, version), for the admin surface’s list view and for the compile-time override merge (DW-086).
Sourcepub fn create_mcp_session(
&self,
session_id: &str,
consumer: &str,
ttl_secs: u64,
client_info: Option<&str>,
) -> Result<(), StoreError>
pub fn create_mcp_session( &self, session_id: &str, consumer: &str, ttl_secs: u64, client_info: Option<&str>, ) -> Result<(), StoreError>
Create a new MCP agent session (DW-087). Inserts a row with
the given session id, consumer, TTL, and optional client info
JSON. created_at, last_used_at, and expires_at are
Unix-epoch SECONDS.
Sourcepub fn touch_mcp_session(&self, session_id: &str) -> Result<bool, StoreError>
pub fn touch_mcp_session(&self, session_id: &str) -> Result<bool, StoreError>
Touch an MCP session: update last_used_at to now. Returns
true if the session exists and is not expired, false
otherwise. An expired session is deleted on touch.
Sourcepub fn delete_mcp_session(&self, session_id: &str) -> Result<(), StoreError>
pub fn delete_mcp_session(&self, session_id: &str) -> Result<(), StoreError>
Delete an MCP session (DW-087 shutdown). Returns Ok
regardless of whether a row was deleted.
Sourcepub fn count_active_mcp_sessions(&self) -> Result<usize, StoreError>
pub fn count_active_mcp_sessions(&self) -> Result<usize, StoreError>
Count active (non-expired) MCP sessions (DW-087).
Sourcepub fn cleanup_expired_mcp_sessions(&self) -> Result<usize, StoreError>
pub fn cleanup_expired_mcp_sessions(&self) -> Result<usize, StoreError>
Delete expired MCP sessions (DW-087). Returns the number of rows deleted.
Sourcepub fn list_active_mcp_sessions(
&self,
) -> Result<Vec<(String, String, i64, i64, i64, Option<String>)>, StoreError>
pub fn list_active_mcp_sessions( &self, ) -> Result<Vec<(String, String, i64, i64, i64, Option<String>)>, StoreError>
List active MCP sessions (DW-087): the admin surface’s
GET /mcp/sessions view. Returns (session_id, consumer,
created_at, last_used_at, expires_at, client_info) for
non-expired sessions, ordered by created_at descending.
Sourcepub fn upsert_workspace(
&self,
name: &str,
description: &str,
active: bool,
) -> Result<(), StoreError>
pub fn upsert_workspace( &self, name: &str, description: &str, active: bool, ) -> Result<(), StoreError>
Insert or replace a workspace row. The default workspace is
seeded by the manager on first open; this method is the
manager’s persistence path for create/update.
Sourcepub fn delete_workspace_row(&self, name: &str) -> Result<bool, StoreError>
pub fn delete_workspace_row(&self, name: &str) -> Result<bool, StoreError>
Delete a workspace row. Returns true if a row was deleted.
Sourcepub fn list_workspace_rows(&self) -> Result<Vec<WorkspaceRow>, StoreError>
pub fn list_workspace_rows(&self) -> Result<Vec<WorkspaceRow>, StoreError>
List all workspace rows.
Sourcepub fn get_workspace_row(
&self,
name: &str,
) -> Result<Option<WorkspaceRow>, StoreError>
pub fn get_workspace_row( &self, name: &str, ) -> Result<Option<WorkspaceRow>, StoreError>
Get a single workspace row by name.
Sourcepub fn upsert_role(
&self,
name: &str,
permissions_json: &str,
) -> Result<(), StoreError>
pub fn upsert_role( &self, name: &str, permissions_json: &str, ) -> Result<(), StoreError>
Insert or replace an RBAC role row. The permissions are stored
as a JSON array of {"action":"...","workspace":"..."}.
Sourcepub fn delete_role_row(&self, name: &str) -> Result<bool, StoreError>
pub fn delete_role_row(&self, name: &str) -> Result<bool, StoreError>
Delete an RBAC role row. Returns true if a row was deleted.
Sourcepub fn list_role_rows(&self) -> Result<Vec<RoleRow>, StoreError>
pub fn list_role_rows(&self) -> Result<Vec<RoleRow>, StoreError>
List all RBAC role rows.
Sourcepub fn upsert_principal(
&self,
identity: &str,
roles_json: &str,
) -> Result<(), StoreError>
pub fn upsert_principal( &self, identity: &str, roles_json: &str, ) -> Result<(), StoreError>
Insert or replace a principal row. The roles are stored as a JSON array of role-name strings.
Sourcepub fn get_principal_row(
&self,
identity: &str,
) -> Result<Option<PrincipalRow>, StoreError>
pub fn get_principal_row( &self, identity: &str, ) -> Result<Option<PrincipalRow>, StoreError>
Get a single principal row by identity.
Sourcepub fn list_principal_rows(&self) -> Result<Vec<PrincipalRow>, StoreError>
pub fn list_principal_rows(&self) -> Result<Vec<PrincipalRow>, StoreError>
List all principal rows.
Sourcepub fn append_workspace_audit(
&self,
timestamp_ms: i64,
principal: &str,
action: &str,
workspace: &str,
before: Option<&str>,
after: Option<&str>,
request_id: &str,
) -> Result<i64, StoreError>
pub fn append_workspace_audit( &self, timestamp_ms: i64, principal: &str, action: &str, workspace: &str, before: Option<&str>, after: Option<&str>, request_id: &str, ) -> Result<i64, StoreError>
Append an audit entry. Returns the assigned sequence number.
Sourcepub fn query_workspace_audit(
&self,
workspace: Option<&str>,
since_ms: Option<i64>,
until_ms: Option<i64>,
limit: i64,
) -> Result<Vec<AuditRow>, StoreError>
pub fn query_workspace_audit( &self, workspace: Option<&str>, since_ms: Option<i64>, until_ms: Option<i64>, limit: i64, ) -> Result<Vec<AuditRow>, StoreError>
Query audit entries, optionally filtered by workspace and
bounded by a time range. Returns entries ordered by seq
descending (newest first), capped at limit.
Sourcepub fn try_acquire_leader(
&self,
instance_id: &str,
ttl_ms: i64,
) -> Result<LeaderRow, StoreError>
pub fn try_acquire_leader( &self, instance_id: &str, ttl_ms: i64, ) -> Result<LeaderRow, StoreError>
Try to acquire leadership. Returns Ok(LeaderRow) if this
instance now holds the lease; returns Err(String) with
“instance_id:expires_at_ms” of the current holder if another
instance holds a valid (non-expired) lease.
Sourcepub fn renew_leader_lease(
&self,
instance_id: &str,
ttl_ms: i64,
) -> Result<LeaderRow, StoreError>
pub fn renew_leader_lease( &self, instance_id: &str, ttl_ms: i64, ) -> Result<LeaderRow, StoreError>
Renew the leader lease. Returns Ok(LeaderRow) with the new
expiry if this instance still holds the lease; Err if the
lease was lost (expired or stolen).
Sourcepub fn step_down_leader(&self, instance_id: &str) -> Result<(), StoreError>
pub fn step_down_leader(&self, instance_id: &str) -> Result<(), StoreError>
Voluntarily release the lease (graceful shutdown). Returns
Ok(()) if the lease was released, Err if this instance
did not hold the lease.
Sourcepub fn current_leader(&self) -> Result<Option<LeaderRow>, StoreError>
pub fn current_leader(&self) -> Result<Option<LeaderRow>, StoreError>
Get the current leader (if any), or None if no valid
(non-expired) lease exists.
Sourcepub fn save_generation_counter(&self, generation: u64) -> Result<(), StoreError>
pub fn save_generation_counter(&self, generation: u64) -> Result<(), StoreError>
Persist the current config generation counter (SCALE-06, #185). This survives controller restarts so the generation counter does not reset to 1.
Sourcepub fn load_generation_counter(&self) -> Result<Option<u64>, StoreError>
pub fn load_generation_counter(&self) -> Result<Option<u64>, StoreError>
Load the persisted config generation counter (SCALE-06, #185).
Returns None if no counter has been persisted (fresh store).
Sourcepub fn append_event_wal(
&self,
id: &str,
kind: &str,
gateway: &str,
timestamp_ms: u64,
payload_json: &str,
) -> Result<(), StoreError>
pub fn append_event_wal( &self, id: &str, kind: &str, gateway: &str, timestamp_ms: u64, payload_json: &str, ) -> Result<(), StoreError>
Append a critical event to the WAL before emission. The event
is persisted as un-acked (acked = 0); the deliverer marks it
acked after dispatch. payload_json is the JSON-serialized
EventPayload.
Sourcepub fn ack_event_wal(&self, id: &str) -> Result<usize, StoreError>
pub fn ack_event_wal(&self, id: &str) -> Result<usize, StoreError>
Mark an event as acked (delivered). Called by the webhook deliverer after the event has been dispatched to matching targets. Returns the number of rows updated (0 if the event was already acked or doesn’t exist).
Sourcepub fn unacked_events_wal(&self) -> Result<Vec<EventWalRow>, StoreError>
pub fn unacked_events_wal(&self) -> Result<Vec<EventWalRow>, StoreError>
Load all un-acked events from the WAL, ordered by timestamp (oldest first). Called on startup to replay events that were not delivered before the previous process exited.
Sourcepub fn purge_acked_events_wal(
&self,
older_than_ms: u64,
) -> Result<usize, StoreError>
pub fn purge_acked_events_wal( &self, older_than_ms: u64, ) -> Result<usize, StoreError>
Purge acked events older than the given timestamp. Called periodically to keep the WAL from growing unbounded. Returns the number of rows purged.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for StateStore
impl RefUnwindSafe for StateStore
impl Send for StateStore
impl Sync for StateStore
impl Unpin for StateStore
impl UnwindSafe for StateStore
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more