Skip to main content

MemoryStore

Struct MemoryStore 

Source
pub struct MemoryStore {
    pub min_part: u64,
    pub max_parts: usize,
    /* private fields */
}

Fields§

§min_part: u64§max_parts: usize

Implementations§

Source§

impl MemoryStore

Source

pub fn backdate_epoch(&self, key: &str, secs: u64)

Age an object’s last-modified stamp. Liveness here is judged against the STORE’s clock (A8), so a test about a dead holder has to be able to move that clock rather than sleep.

Source

pub fn plant_lifecycle_rule(&self, rule: LifecycleView)

Plant a lifecycle rule the way a customer’s own fleet policy would. D8’s destroyer is a rule flint never wrote.

Source

pub fn new() -> Self

Source

pub fn with_if_match_missing_as_412(self) -> Self

Answer If-Match on a missing key with 412, as Ozone’s S3 gateway does, instead of S3’s 404 NoSuchKey. See if_match_missing_412.

Source

pub fn with_part_parallelism(self, n: usize) -> Self

Stage this many parts of one compose concurrently (the S3 backend’s with_part_parallelism). Clamped to at least 1.

Source

pub fn with_upload_inflight_max_bytes(self, n: u64) -> Self

Bound the bytes the upload path holds at once (the S3 backend’s with_upload_inflight_max_bytes; see gate.rs). 0 = no gate.

Source

pub fn inject_put_whole_delay_ms(&self, ms: u64)

Every whole PUT from now on sleeps ms first — the write side’s inject_get_range_delay_ms: whole bodies that overlap are in flight together for the whole delay, so the upload byte gate’s high-water mark reads the caller’s bound rather than the scheduler’s luck.

Source

pub fn strip_version_ids(&self, on: bool)

Every write from here on reports no version id — a proxy that strips the header (D8’s refusal arm).

Source

pub fn fail_lifecycle_writes(&self, on: bool)

Lifecycle writes fail from here on; reads keep working.

Source

pub fn inject_torn_complete(&self)

Next compose: Complete LANDS but the response is lost.

Source

pub fn inject_crash_before_complete(&self)

Next compose: dies before Complete — MPU left pending.

Source

pub fn inject_compose_swept(&self)

Next compose: the operator’s abort sweep takes the assembly before Complete — NoSuchUpload, S3’s answer, and nothing lands.

Source

pub fn inject_get_range_failure(&self)

Step-11 drills: the NEXT get_range fails with a transport error — a single failure is absorbed by the chunk-retry loop.

Source

pub fn inject_get_range_failures(&self, n: u64)

The next n get_range calls fail with a transport error — exceed the chunk-retry budget to force the truncate-back path.

Source

pub fn inject_get_range_delay_ms(&self, ms: u64)

Every get_range from now on sleeps ms first. Unlike the one-shot stall this is persistent, and it is what makes a fan-out OBSERVABLE: calls that overlap are in flight together for the whole delay, so peak_get_range_in_flight reads the caller’s bound rather than the scheduler’s luck.

Source

pub fn inject_put_hold(&self, on: bool)

Every whole PUT from now on parks until release_held_puts (false lets new PUTs through again; a PUT already parked stays parked). Checked at the start of each PUT, so a test can stall one task’s upload, let the next caller’s through at once, and release the stalled one when it chooses.

Source

pub fn inject_put_hold_matching(&self, key_contains: &str)

Like inject_put_hold, but only for keys containing key_contains. inject_put_hold(false) ends it.

Source

pub fn held_puts(&self) -> usize

How many whole PUTs are parked right now.

Source

pub fn release_held_puts(&self)

Let every parked PUT land.

Source

pub fn peak_get_range_in_flight(&self) -> u64

The most get_range calls ever in flight at once since the last reset. A fan-out bounded at N reads exactly N here when there is work for N — and exactly 1 when it is not a fan-out at all.

Source

pub fn reset_peak_get_range_in_flight(&self)

Source

pub fn inject_head_failures(&self, n: u64)

The next n HEAD calls fail with a transport error.

The condition this models is not exotic: the foreign-key sweep issues one HEAD per unknown object, which on a large bucket is exactly the shape that earns a 503 SlowDown. The SDK’s default retry absorbs a blip; a sustained throttle outlives it.

Source

pub fn inject_epoch_renew_failures(&self, n: u64)

The next n renewals fail as a transport error — not a 412, so the holder cannot tell “deposed” from “cut off”. Zero clears it.

Source

pub fn inject_put_lands_then_fails(&self, key_contains: &str, n: u64)

The next n whole PUTs STORE THE OBJECT and then report 409.

This is the one failure a conditional writer cannot interpret. S3 answers a contended conditional write with 409 ConditionalRequestConflict, and a lost response to a PUT that landed looks the same from the client: the write is durable and the caller was told it failed. Every other injector here models a failure that did NOT happen server-side; this one models the failure that DID. key_contains narrows it to one object — a batch uploads its packs BEFORE the snapshot CAS, so an untargeted injection would break a pack upload and never reach the write under test.

Source

pub fn inject_get_range_stall(&self, ms: u64)

Step-11 drills: the NEXT get_range stalls ms before serving — a slow hydration to race concurrent I/O and priority against.

Source

pub fn inject_corrupt_body(&self, key: &str, mutate: impl FnOnce(&mut Vec<u8>))

Test surface: the bytes under a key change while its etag and its stored checksum claim do NOT — bit-rot, a broken gateway, a cache serving the wrong body. Nothing on the wire says so: If-Match still matches, and a store that never carried a checksum header validates nothing. Only a reader that checks the body against what the MANIFEST cites can see it.

Source

pub fn raw_put( &self, key: &str, bytes: Bytes, meta: Vec<(String, String)>, ) -> ObjectMeta

Test surface: plant an object directly (foreign writers, torn own states, import fixtures). Stamps go in as given.

Source

pub fn redeem_presigned_put( &self, url: &str, headers: &BTreeMap<String, String>, body: Bytes, ) -> StoreResult<ObjectMeta>

Test surface: REDEEM a URL from ObjectStore::presign_put the way S3 does, so a test can play the client — or the attacker — who holds it.

Without this the double’s presigned URL was a string nothing ever used, and “the URL grants only the bytes it was issued for” could not be asked of it at all. What S3 enforces, and so what this enforces (and nothing more):

  • every header the URL SIGNED must be presented, with the signed value, or the signature does not match (403). An unsigned header binds nothing: the holder simply leaves it out.
  • a presented x-amz-checksum-sha256 must be the base64 SHA-256 of the body (400 BadDigest).
  • a presented If-None-Match: * refuses a key that exists (412).

Header names are compared case-insensitively, as HTTP does.

Source

pub fn expire_noncurrent(&self, older_than_secs: u64) -> Vec<(String, String)>

Test surface: the NONCURRENT-VERSION LIFECYCLE BACKSTOP (D8), modelled as an explicit method because it is a timer in reality and an untestable one if left implicit.

The hazard it exists to demonstrate is INVERTED from the eager-prefix design’s: gated staging makes the cited version noncurrent the moment a newer generation is staged, so a NoncurrentVersionExpiration rule on files/ runs a clock against live cited data — and never against the newest uncited bytes, which are current and which no lifecycle rule can reach. Reaping a cited noncurrent version dangles the manifest; that is Inv_CitedVersionLives’s required-firing mutation and leg B23’s abandoned-mid-stage endgame.

Returns the (key, version_id) pairs reaped.

Source

pub fn version_count(&self, key: &str) -> usize

Test surface: how many versions a key currently holds (leg B21’s oracle — steady state must return to ONE live version per key, reclaimed by flint’s exact per-citation GC, NOT by waiting for the backstop).

Source

pub fn raw_complete_upload(&self, upload_id: &str) -> StoreResult<ObjectMeta>

Test surface: a DEPOSED writer’s late CompleteMultipartUpload. Assembles whatever parts exist (unconditionally — the deposed straggler of the A8 drill carries no working guard); answers NoSuchUpload if the assembly was fenced away, exactly S3’s answer after the takeover abort-sweep.

Source

pub fn raw_begin_upload(&self, key: &str) -> String

Test surface: an orphan MPU (for the A9 sweep tests).

Source§

impl MemoryStore

Source

pub fn op_counts(&self) -> BTreeMap<&'static str, u64>

Call counts since construction or the last reset.

Source

pub fn reset_op_counts(&self)

Source

pub fn total_ops(&self) -> u64

Trait Implementations§

Source§

impl Default for MemoryStore

Source§

fn default() -> Self

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

impl ObjectStore for MemoryStore

Source§

fn presign_get<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ttl_secs: u64, ) -> Pin<Box<dyn Future<Output = StoreResult<String>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

A stand-in URL: deterministic, unmistakably not real, and refused for a key that does not exist. A test can assert that the right key was signed and that a missing object is not advertised; whether a git client can actually fetch it is a question only a real store answers, and forge’s storm leg is where that is asked.

Source§

fn presign_put<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, ttl_secs: u64, sha256: &'life2 [u8; 32], ) -> Pin<Box<dyn Future<Output = StoreResult<PresignedPut>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

A stand-in URL for a write. Unlike the read side it does NOT require the object to exist — that is the whole point of an upload. The headers it binds are written INTO the URL as h. parameters, which is how redeem_presigned_put plays S3’s signature: a signed header must be presented as signed.

Source§

fn get_range_segments<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, offset: u64, len: u64, if_match: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<Vec<Bytes>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Real S3 always delivers a ranged body as MANY frames. This double handed back exactly one, so a caller that walks segments and advances a running offset was never actually exercised against it — a double missing a property its subject always has, which passes for the wrong reason. Built on get_range so every injected failure, stall and in-flight count still applies.

Source§

fn delete_many<'life0, 'life1, 'async_trait>( &'life0 self, keys: &'life1 [String], ) -> Pin<Box<dyn Future<Output = StoreResult<DeleteManyReport>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

One request per thousand keys, as S3’s DeleteObjects costs — so a request census over the double reads what the wire would.

Source§

fn request_counts(&self) -> Option<RequestCounts>

Requests this store has sent since it was built, by kind (counters.rs). None = a store that does not count.
Source§

fn put_whole<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, body: Bytes, condition: &'life2 PutCondition, stamps: &'life3 GenerationStamps, crc64: u64, ) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Whole-object publish (below the multipart threshold). crc64 is validated server-side; stamps ride as metadata.
Source§

fn copy_object<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, src_key: &'life1 str, src_if_match: Option<&'life2 str>, dst_key: &'life3 str, condition: &'life4 PutCondition, stamps: &'life5 GenerationStamps, ) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait,

Assemble and publish one generation from local dirty bytes plus server-side clean copies. MUST abort its partial assembly on every failure path (A9) — an error return means nothing is left pending under the key by this call. Server-side copy of a WHOLE object to a DIFFERENT key. Read more
Source§

fn compose_generation<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, spec: &'life1 ComposeSpec<'life2>, ) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Source§

fn head<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn get_whole<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, if_match: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = StoreResult<(ObjectMeta, Bytes)>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Whole-object read, optionally guarded (hydration always guards: a 412 here is S3-WINS — the foreign-overwrite posture, opposite of the publish path).
Source§

fn get_range<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, offset: u64, len: u64, if_match: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<Bytes>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Ranged read (step 11’s streaming restore — a multi-GiB hydration must never buffer the whole object). ALWAYS guarded: each chunk’s If-Match pins the same object version end-to-end; a 412 mid-restore is the S3-wins foreign-overwrite signal. The caller never requests past the object’s end.
Source§

fn list<'life0, 'life1, 'async_trait>( &'life0 self, prefix: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<Vec<ListedObject>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn delete<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn delete_if_match<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, etag: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

DELETE key only while its current ETag is etag (If-Match): PreconditionFailed once the object has moved on, NotFound when there is nothing to delete. Read more
Source§

fn head_version<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, version_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<ObjectMeta>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

HEAD one specific version.
Source§

fn get_version<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, version_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<(ObjectMeta, Bytes)>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

GET one specific version, when the backend keeps versions. Lean’s readers resolve citations by etag alone (version-pinned reads went with gated mode, 2026-09-13); the method stays for tools and probes.
Source§

fn delete_version<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, version_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

DELETE one specific version — the exact reclamation flint’s own per-citation GC uses. Free, and the ONLY reaper that can tell cited from uncited; lifecycle cannot, which is why the noncurrent rule is a long backstop rather than the mechanism (D8).
Source§

fn list_versions<'life0, 'life1, 'async_trait>( &'life0 self, prefix: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<Vec<ListedVersion>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Every version under a prefix, current and noncurrent, oldest first per key. The claim-time/DR fallback when orphans.json is missing or stale — the expensive path, which is why the durable summary is written eagerly.
Source§

fn list_uploads<'life0, 'life1, 'async_trait>( &'life0 self, prefix: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<Vec<PendingUpload>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

A9 hygiene: every in-progress assembly under the prefix.
Source§

fn abort_upload<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _key: &'life1 str, upload_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Abort one assembly. Aborting an already-absent upload is Ok — the sweep and the abort-on-failure paths both race the lifecycle rule.
Source§

fn bootstrap<'life0, 'life1, 'async_trait>( &'life0 self, _prefix: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<BootstrapReport>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

A9: verify/create the bucket posture (lifecycle abort rule, versioning, encryption notes, IAM probe). Named prefix so probes stay under the tier’s namespace.
Source§

fn lifecycle_rules<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = StoreResult<Vec<LifecycleView>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Every lifecycle rule on the bucket, reduced to LifecycleView. Read more
Source§

fn ensure_noncurrent_retention<'life0, 'life1, 'async_trait>( &'life0 self, prefix: &'life1 str, days: u64, ) -> Pin<Box<dyn Future<Output = StoreResult<RetentionOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Provision the noncurrent-version retention backstop on prefix with read-merge-append, and report what is installed. Read more
Source§

fn epoch_read<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = StoreResult<Option<EpochState>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn epoch_acquire<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, holder_id: &'life2 str, supersede: Option<&'life3 EpochState>, ) -> Pin<Box<dyn Future<Output = StoreResult<EpochLease>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Claim: supersede: None creates (If-None-Match:*); Some replaces the OBSERVED state via CAS on its token — the caller (step 7) is responsible for having JUDGED that holder dead against the store’s clock. The new epoch is observed+1.
Source§

fn epoch_renew<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, lease: &'life2 EpochLease, echo: Option<&'life3 str>, ) -> Pin<Box<dyn Future<Output = StoreResult<EpochLease>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Heartbeat CAS. PreconditionFailed means deposed: self-fence. Read more
Source§

fn epoch_release<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, lease: &'life2 EpochLease, ) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Mark the cell released: a clean handoff. The epoch NUMBER must survive (deleting the cell would restart numbering at 1 and break the monotonicity every publish stamp depends on), and the write must be guarded on lease’s own token so a deposed holder cannot mark a live successor’s cell.
Source§

fn epoch_handoff<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, lease: &'life2 EpochLease, echo: Option<&'life3 str>, ) -> Pin<Box<dyn Future<Output = StoreResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

The per-BARRIER release (lean, design 2026-09-13 §4): mark the cell released like ObjectStore::epoch_release, but hand it to the queue head (handoff = waiters[0], the rest stay queued) and KEEP echo — the cell is at rest between every barrier now, so the last holder’s echo is the only thing that tells an operator which binary ran the last boundary. Guarded on the lease token like every other transition. Default: the plain release.
Source§

fn epoch_enqueue<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, observed: &'life2 EpochState, holder_id: &'life3 str, ) -> Pin<Box<dyn Future<Output = StoreResult<EpochState>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Append holder_id to the cell’s FIFO of waiters, by CAS on the OBSERVED token, and return the cell as rewritten. A holder that is already queued is not appended twice. The write moves the token: a live holder’s next renew/handoff 412s, re-reads, and adopts the new token with the longer queue (lean lease.rs). Default: unsupported — a backend without a queue serialises claimants by the quiet-poll rule alone.
Source§

fn min_part_size(&self) -> u64

Backend part granularity for the A11 part-size grid.
Source§

fn max_parts(&self) -> usize

Source§

fn upload_gate(&self) -> Option<Arc<ByteGate>>

The store’s upload bytes-in-flight gate (gate::ByteGate), when it was built with one. The store charges every local part of a compose to it; a caller that reads whole bodies ITSELF before put_whole (lean’s upload_one) takes this so those bodies are charged to the SAME budget, and the bound is one number rather than two that must be set together. None = the upload path is bounded only by its counts.

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> 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> Same for T

Source§

type Output = T

Should always be Self
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.