Skip to main content

EvaluationSession

Struct EvaluationSession 

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

Request-scoped fact loading and caching state.

A session is intended to live for one request or one authorization pass. It owns registered fact sources and caches loaded facts by key type. The cache is deliberately not process-global. Cached facts and cached errors are dropped with the session, so permission revocations or backend changes are observed by the next request’s session rather than being held process-wide.

There is intentionally no time-based (TTL) cache: freshness is governed by session lifetime — drop the session to drop its cache. If you need caching that outlives a single session (a process-wide cache with a TTL, say), layer it inside a FactSource implementation. A source can hold its own expiring cache and be shared across sessions via Self::register_arc, which keeps the session a simple request-scoped layer on top.

Implementations§

Source§

impl EvaluationSession

Source

pub fn new() -> Self

Creates an empty request-scoped session.

Source

pub fn empty() -> Self

Creates an explicitly empty request-scoped session.

This is equivalent to Self::new. It can make call sites clearer when only RBAC/ABAC policies are expected and no fact sources are registered. For very hot RBAC/ABAC-only loops, use Self::shared_empty to avoid allocating a new empty session per call.

Examples found in repository?
examples/factsource_n_plus_one.rs (line 237)
212async fn main() {
213    // Same supplier, same hierarchy, same invoices for both shapes.
214    let supplier_org = Uuid::new_v4();
215    let customer = Uuid::new_v4();
216    let supplier = Supplier {
217        user_id: Uuid::new_v4(),
218        org_id: supplier_org,
219    };
220    let routes = std::collections::HashMap::from([(supplier_org, customer)]);
221    let hierarchy = Arc::new(HierarchyService::new(routes));
222
223    let invoices: Vec<Invoice> = (0..25)
224        .map(|_| Invoice {
225            id: Uuid::new_v4(),
226            customer_id: customer,
227        })
228        .collect();
229
230    // ---- WRONG ----
231    let mut wrong_checker = PermissionChecker::<Supplier, Invoice, ViewAction, ()>::new();
232    wrong_checker.add_policy(WrongSupplierPolicy {
233        hierarchy: Arc::clone(&hierarchy),
234    });
235
236    hierarchy.reset();
237    let session = EvaluationSession::empty();
238    let visible = wrong_checker
239        .filter_authorized_in_session_by_resource(
240            &session,
241            &supplier,
242            &ViewAction,
243            invoices.clone(),
244            &(),
245            |i| i,
246        )
247        .await;
248    let wrong_calls = hierarchy.calls();
249    println!(
250        "[wrong] {} invoices -> {} hierarchy lookups (N+1, redundant)",
251        visible.len(),
252        wrong_calls,
253    );
254    // Check the lesson (call count) before the bookkeeping (item count)
255    // so a regression in the dedup logic surfaces here, not in a
256    // confusing length mismatch.
257    assert_eq!(
258        wrong_calls, 25,
259        "the wrong shape pays one hierarchy call per item",
260    );
261    assert_eq!(visible.len(), 25);
262
263    // ---- RIGHT ----
264    let mut right_checker = PermissionChecker::<Supplier, Invoice, ViewAction, ()>::new();
265    right_checker.add_policy(RightSupplierPolicy);
266
267    hierarchy.reset();
268    let load_many_calls = Arc::new(AtomicUsize::new(0));
269    let session = EvaluationSession::builder()
270        .with_arc::<CustomerForOrg>(Arc::new(CustomerForOrgSource {
271            hierarchy: Arc::clone(&hierarchy),
272            load_many_calls: Arc::clone(&load_many_calls),
273        }))
274        .build();
275    let visible = right_checker
276        .filter_authorized_in_session_by_resource(
277            &session,
278            &supplier,
279            &ViewAction,
280            invoices,
281            &(),
282            |i| i,
283        )
284        .await;
285    let right_calls = hierarchy.calls();
286    let batch_calls = load_many_calls.load(Ordering::SeqCst);
287    println!(
288        "[right] {} invoices ->  {} hierarchy lookup  ({} batched load_many call, deduped through the session)",
289        visible.len(),
290        right_calls,
291        batch_calls,
292    );
293    assert_eq!(
294        right_calls, 1,
295        "the session deduplicates: one supplier_org, one backend call",
296    );
297    assert_eq!(
298        batch_calls, 1,
299        "the session batches: one load_many call covering the unique key set",
300    );
301    assert_eq!(visible.len(), 25);
302}
More examples
Hide additional examples
examples/lookup_in_ram.rs (line 218)
155async fn main() {
156    // Build a small population.
157    let alice = User {
158        id: Uuid::new_v4(),
159        is_admin: false,
160    };
161    let admin = User {
162        id: Uuid::new_v4(),
163        is_admin: true,
164    };
165    let docs: Vec<Document> = (0..7)
166        .map(|i| Document {
167            id: Uuid::new_v4(),
168            title: format!("doc-{i}"),
169        })
170        .collect();
171
172    // Alice is a viewer of docs[1], docs[3], docs[5].
173    let viewer_doc_ids: Vec<Uuid> = [&docs[1], &docs[3], &docs[5]]
174        .into_iter()
175        .map(|d| d.id)
176        .collect();
177
178    let viewers: HashMap<Uuid, Vec<Uuid>> = viewer_doc_ids
179        .iter()
180        .map(|doc_id| (*doc_id, vec![alice.id]))
181        .collect();
182
183    let viewer_lookup_index: HashMap<Uuid, Vec<Uuid>> =
184        HashMap::from([(alice.id, viewer_doc_ids.clone())]);
185
186    // Document catalog used by the hydrator. In production this is a
187    // database call: `SELECT * FROM docs WHERE id = ANY($1)`.
188    let catalog: Arc<HashMap<Uuid, Document>> =
189        Arc::new(docs.iter().map(|d| (d.id, d.clone())).collect());
190
191    let lookup = InMemoryViewerLookup {
192        per_user: viewer_lookup_index,
193    };
194
195    // Hydrator closure: maps a slice of ids to `Vec<Option<Document>>`.
196    // `None` would represent an id deleted between enumeration and the
197    // catalog fetch; the in-memory catalog here always resolves.
198    let hydrator = {
199        let catalog = Arc::clone(&catalog);
200        move |ids: &[Uuid]| {
201            let catalog = Arc::clone(&catalog);
202            let ids = ids.to_vec();
203            async move {
204                Ok::<_, std::convert::Infallible>(
205                    ids.iter().map(|id| catalog.get(id).cloned()).collect(),
206                )
207            }
208        }
209    };
210
211    // Compose policies: admin override OR viewer relation. The lookup
212    // source only enumerates the viewer axis — admin overrides apply only
213    // to point checks.
214    let mut checker = PermissionChecker::<User, Document, View, ()>::new();
215    checker.add_policy(AdminPolicy);
216    checker.add_policy(ViewerPolicy { viewers });
217
218    let session = EvaluationSession::empty();
219    let page_size = NonZeroUsize::new(2).unwrap();
220
221    // (1) Alice lists her visible documents via lookup_authorized.
222    let alice_visible = checker
223        .lookup_authorized(&session, &alice, &View, &(), &lookup, page_size, &hydrator)
224        .await
225        .expect("lookup ok");
226    println!("Alice sees {} document(s):", alice_visible.len());
227    for doc in &alice_visible {
228        println!("  - {} ({})", doc.title, doc.id);
229    }
230    let alice_visible_ids: Vec<Uuid> = alice_visible.iter().map(|doc| doc.id).collect();
231    assert_eq!(
232        alice_visible_ids, viewer_doc_ids,
233        "the lookup + policy stack should authorize exactly the viewer-granted documents, in source order"
234    );
235
236    // (2) Admin lists "their visible documents" via the same lookup.
237    // The viewer lookup does not enumerate documents for the admin (no
238    // viewer relation), so this listing returns empty — correctly,
239    // because lookup is bounded by what it enumerates. To enumerate
240    // "everything an admin can see", the production code would either
241    // route admin requests to a different source or simply skip the
242    // lookup path and list directly.
243    let admin_via_lookup = checker
244        .lookup_authorized(&session, &admin, &View, &(), &lookup, page_size, &hydrator)
245        .await
246        .expect("lookup ok");
247    println!(
248        "\nAdmin via the viewer-lookup sees {} document(s) — this is bounded \
249         by what the source enumerates; admin grants still apply at point checks.",
250        admin_via_lookup.len()
251    );
252    assert!(
253        admin_via_lookup.is_empty(),
254        "the viewer lookup enumerates nothing for the admin, so the listing is empty"
255    );
256
257    // (3) Point check confirms the admin policy is alive: pick a document
258    // the admin has no viewer relation on.
259    let any_doc = &docs[0];
260    let admin_point = checker
261        .evaluate_in_session(&session, &admin, &View, any_doc, &())
262        .await;
263    println!(
264        "\nAdmin point check on '{}': {}",
265        any_doc.title,
266        if admin_point.is_granted() {
267            "Granted"
268        } else {
269            "Denied"
270        }
271    );
272    admin_point.assert_granted_by("AdminPolicy");
273
274    // (4) Page-oriented streaming. Drive the lookup one candidate page at
275    // a time — useful when you want to flush results to a response writer
276    // as they are confirmed.
277    println!("\nStreaming Alice's visible documents page-by-page:");
278    let mut cursor: Option<Vec<u8>> = None;
279    let mut page_index = 0;
280    let mut streamed_total = 0;
281    loop {
282        let page = checker
283            .lookup_authorized_page(
284                &session,
285                &alice,
286                &View,
287                &(),
288                &lookup,
289                cursor.as_deref(),
290                page_size,
291                &hydrator,
292            )
293            .await
294            .expect("lookup_authorized_page ok");
295        println!("  page {page_index}: {} authorized", page.resources.len());
296        page_index += 1;
297        streamed_total += page.resources.len();
298        match page.next_cursor {
299            None => break,
300            Some(next) => cursor = Some(next),
301        }
302    }
303    // 3 candidate ids paged 2-at-a-time: two candidate pages, same total as
304    // the collecting `lookup_authorized` call above.
305    assert_eq!(page_index, 2);
306    assert_eq!(streamed_total, viewer_doc_ids.len());
307}
Source

pub fn shared_empty() -> &'static Self

Returns a process-wide empty session for hot paths that never use fact sources.

This avoids allocating a new empty session for RBAC/ABAC-only checks in tight loops. It is only safe when no fact-backed policies are expected: calling Self::register, Self::register_arc, Self::replace, or Self::replace_arc on this session panics.

The panic is deliberate. Registering on the shared handle is a programming error, not a runtime condition — code that registers sources should own a Self::new session, and this handle exists only for fact-free hot paths. The non-panicking Self::try_register / Self::try_replace family still returns FactSourceRegistrationError::SharedEmptySession here rather than panicking, for callers that want to handle it. A type-state split (a separate “registrable” type) was considered but would push that distinction into every signature that accepts a &EvaluationSession, defeating the drop-in substitutability that makes this handle useful.

Source

pub fn builder() -> EvaluationSessionBuilder

Starts building a request-scoped session with all fact sources declared in one place.

Examples found in repository?
examples/actix_web.rs (line 241)
240    fn request_session(&self) -> EvaluationSession {
241        EvaluationSession::builder()
242            .with_arc::<PostRelationship>(Arc::clone(&self.relationships))
243            .build()
244    }
More examples
Hide additional examples
examples/postgres_bulk_rebac.rs (line 158)
157fn session_with(source: &Arc<dyn FactSource<RelationshipKey>>) -> EvaluationSession {
158    EvaluationSession::builder()
159        .with_arc::<RelationshipKey>(Arc::clone(source))
160        .build()
161}
examples/axum.rs (line 252)
251    fn request_session(&self) -> EvaluationSession {
252        EvaluationSession::builder()
253            .with_arc::<InvoiceRelationship>(Arc::clone(&self.invoice_relationships))
254            .build()
255    }
examples/in_ram_rebac.rs (line 74)
73fn request_session(relationships: &Arc<dyn FactSource<RelationshipKey>>) -> EvaluationSession {
74    EvaluationSession::builder()
75        .with_arc::<RelationshipKey>(Arc::clone(relationships))
76        .build()
77}
examples/factsource_n_plus_one.rs (line 269)
212async fn main() {
213    // Same supplier, same hierarchy, same invoices for both shapes.
214    let supplier_org = Uuid::new_v4();
215    let customer = Uuid::new_v4();
216    let supplier = Supplier {
217        user_id: Uuid::new_v4(),
218        org_id: supplier_org,
219    };
220    let routes = std::collections::HashMap::from([(supplier_org, customer)]);
221    let hierarchy = Arc::new(HierarchyService::new(routes));
222
223    let invoices: Vec<Invoice> = (0..25)
224        .map(|_| Invoice {
225            id: Uuid::new_v4(),
226            customer_id: customer,
227        })
228        .collect();
229
230    // ---- WRONG ----
231    let mut wrong_checker = PermissionChecker::<Supplier, Invoice, ViewAction, ()>::new();
232    wrong_checker.add_policy(WrongSupplierPolicy {
233        hierarchy: Arc::clone(&hierarchy),
234    });
235
236    hierarchy.reset();
237    let session = EvaluationSession::empty();
238    let visible = wrong_checker
239        .filter_authorized_in_session_by_resource(
240            &session,
241            &supplier,
242            &ViewAction,
243            invoices.clone(),
244            &(),
245            |i| i,
246        )
247        .await;
248    let wrong_calls = hierarchy.calls();
249    println!(
250        "[wrong] {} invoices -> {} hierarchy lookups (N+1, redundant)",
251        visible.len(),
252        wrong_calls,
253    );
254    // Check the lesson (call count) before the bookkeeping (item count)
255    // so a regression in the dedup logic surfaces here, not in a
256    // confusing length mismatch.
257    assert_eq!(
258        wrong_calls, 25,
259        "the wrong shape pays one hierarchy call per item",
260    );
261    assert_eq!(visible.len(), 25);
262
263    // ---- RIGHT ----
264    let mut right_checker = PermissionChecker::<Supplier, Invoice, ViewAction, ()>::new();
265    right_checker.add_policy(RightSupplierPolicy);
266
267    hierarchy.reset();
268    let load_many_calls = Arc::new(AtomicUsize::new(0));
269    let session = EvaluationSession::builder()
270        .with_arc::<CustomerForOrg>(Arc::new(CustomerForOrgSource {
271            hierarchy: Arc::clone(&hierarchy),
272            load_many_calls: Arc::clone(&load_many_calls),
273        }))
274        .build();
275    let visible = right_checker
276        .filter_authorized_in_session_by_resource(
277            &session,
278            &supplier,
279            &ViewAction,
280            invoices,
281            &(),
282            |i| i,
283        )
284        .await;
285    let right_calls = hierarchy.calls();
286    let batch_calls = load_many_calls.load(Ordering::SeqCst);
287    println!(
288        "[right] {} invoices ->  {} hierarchy lookup  ({} batched load_many call, deduped through the session)",
289        visible.len(),
290        right_calls,
291        batch_calls,
292    );
293    assert_eq!(
294        right_calls, 1,
295        "the session deduplicates: one supplier_org, one backend call",
296    );
297    assert_eq!(
298        batch_calls, 1,
299        "the session batches: one load_many call covering the unique key set",
300    );
301    assert_eq!(visible.len(), 25);
302}
examples/rebac_policy.rs (line 148)
106async fn main() {
107    println!("=== ReBAC Policy Example ===\n");
108
109    let owner = User {
110        id: Uuid::new_v4(),
111        name: "Alice",
112    };
113    let contributor = User {
114        id: Uuid::new_v4(),
115        name: "Bob",
116    };
117    let viewer = User {
118        id: Uuid::new_v4(),
119        name: "Charlie",
120    };
121    let outsider = User {
122        id: Uuid::new_v4(),
123        name: "Dave",
124    };
125    let project = Project {
126        id: Uuid::new_v4(),
127        name: "Sample Project",
128    };
129
130    let relationships = HashSet::from([
131        ProjectRelationship {
132            subject_id: owner.id,
133            resource_id: project.id,
134            relation: Relation::Owner,
135        },
136        ProjectRelationship {
137            subject_id: contributor.id,
138            resource_id: project.id,
139            relation: Relation::Contributor,
140        },
141        ProjectRelationship {
142            subject_id: viewer.id,
143            resource_id: project.id,
144            relation: Relation::Viewer,
145        },
146    ]);
147
148    let session = EvaluationSession::builder()
149        .with::<ProjectRelationship, _>(ProjectRelationshipSource::new(relationships.clone()))
150        .build();
151
152    // Editing requires an owner OR contributor relationship; a viewer
153    // relationship exists in the store but grants nothing here.
154    let mut checker = PermissionChecker::<User, Project, EditAction, ()>::new();
155    checker.add_policy(RebacPolicy::new(
156        |user: &User| user.id,
157        |project: &Project| project.id,
158        Relation::Owner,
159    ));
160    checker.add_policy(RebacPolicy::new(
161        |user: &User| user.id,
162        |project: &Project| project.id,
163        Relation::Contributor,
164    ));
165
166    // (user, relationship held, expected outcome)
167    let cases = [
168        (&owner, "owner", true),
169        (&contributor, "contributor", true),
170        (&viewer, "viewer", false),
171        (&outsider, "none", false),
172    ];
173    for (user, held, expected_granted) in cases {
174        println!("Can {} ({held}) edit {}?", user.name, project.name);
175        let decision = checker
176            .evaluate_in_session(&session, user, &EditAction, &project, &())
177            .await;
178        println!(
179            "  -> {}\n",
180            if decision.is_granted() {
181                "GRANTED"
182            } else {
183                "DENIED"
184            }
185        );
186        assert_eq!(decision.is_granted(), expected_granted);
187    }
188
189    // The trace records the facts each policy consulted (the `↳ fact` lines)
190    // alongside its decision — here the viewer's denial shows both
191    // relationship lookups coming back false. Note that no new "loading fact"
192    // lines appear: this re-check runs in the same session, so the facts come
193    // from the session cache.
194    println!("Why {} is denied:", viewer.name);
195    let decision = checker
196        .evaluate_in_session(&session, &viewer, &EditAction, &project, &())
197        .await;
198    println!("{}\n", decision.display_trace());
199
200    println!("=== Error During Relationship Loading ===\n");
201
202    // A failing store must never grant: the load error is carried into the
203    // trace and the decision fails closed to denial — even for the owner.
204    let error_session = EvaluationSession::builder()
205        .with::<ProjectRelationship, _>(ProjectRelationshipSource::new(relationships).with_error())
206        .build();
207    let decision = checker
208        .evaluate_in_session(&error_session, &owner, &EditAction, &project, &())
209        .await;
210    println!("{}", decision.display_trace());
211    decision.assert_denied();
212    decision.assert_trace_contains("simulated relationship store error");
213}
Source

pub fn register<K, S>(&self, source: S)
where K: FactKey, S: FactSource<K> + 'static,

Registers a fact source for one key type.

Panics if a source for K is already registered. Use Self::replace when replacing a source is intentional. Register sources during session setup; registering while loads for the same key type are in flight is not a supported operation and will panic.

This panicking form is meant for session setup, where a failed registration (a duplicate source, or a load already in flight) is a configuration bug that should fail loudly and immediately. Use Self::try_register when registration is driven by runtime input and you want to handle FactSourceRegistrationError rather than panic.

Source

pub fn register_arc<K>(&self, source: Arc<dyn FactSource<K>>)
where K: FactKey,

Registers a shared fact source for one key type.

Panics if a source for K is already registered. Register sources during session setup; use Self::replace_arc only when overwriting is deliberate. Registering while loads for the same key type are in flight is not a supported operation and will panic.

Use this form to share one source instance across many sessions: build the Arc once and Arc::clone it into each request’s session (see EvaluationSessionBuilder::with_arc). Self::register takes the source by value and wraps it in a fresh Arc per call, so it cannot share a single instance; reach for register_arc when the source holds expensive shared state such as a connection pool or its own cache. Like Self::register, it panics on invalid registration; use Self::try_register_arc to handle the error instead.

The registry is keyed by the exact Rust fact key type. If two production backends serve the same logical shape, such as the same RelationshipQuery<UserId, ConversationId, ParticipantRelation>, they cannot both be registered under that exact type in one session. Wrap one ID/relation type or define distinct fact keys so each backend has a separate registry entry.

Source

pub fn try_register<K, S>( &self, source: S, ) -> Result<(), FactSourceRegistrationError>
where K: FactKey, S: FactSource<K> + 'static,

Registers a fact source for one key type, returning an error instead of panicking if registration is invalid.

Source

pub fn try_register_arc<K>( &self, source: Arc<dyn FactSource<K>>, ) -> Result<(), FactSourceRegistrationError>
where K: FactKey,

Registers a shared fact source for one key type, returning an error instead of panicking if registration is invalid.

Source

pub fn replace<K, S>(&self, source: S)
where K: FactKey, S: FactSource<K> + 'static,

Explicitly replaces a fact source for one key type.

Replacing a source clears any cached facts for that key type in this session. Replacing while loads for the same key type are in flight is not a supported operation and will panic.

Source

pub fn replace_arc<K>(&self, source: Arc<dyn FactSource<K>>)
where K: FactKey,

Explicitly replaces a shared fact source for one key type.

Replacing a source clears any cached facts for that key type in this session. Replacing while loads for the same key type are in flight is not a supported operation and will panic.

Source

pub fn try_replace<K, S>( &self, source: S, ) -> Result<(), FactSourceRegistrationError>
where K: FactKey, S: FactSource<K> + 'static,

Explicitly replaces a fact source for one key type, returning an error instead of panicking if replacement is invalid.

Source

pub fn try_replace_arc<K>( &self, source: Arc<dyn FactSource<K>>, ) -> Result<(), FactSourceRegistrationError>
where K: FactKey,

Explicitly replaces a shared fact source for one key type, returning an error instead of panicking if replacement is invalid.

Source

pub async fn get<K>(&self, key: K) -> FactLoadResult<K::Value>
where K: FactKey,

Loads one fact through the session cache.

Examples found in repository?
examples/factsource_n_plus_one.rs (line 197)
189    async fn evaluate(
190        &self,
191        ctx: &EvalCtx<'_, Supplier, Invoice, ViewAction, ()>,
192    ) -> PolicyEvalResult {
193        // Ask the session, not the backend service directly. The
194        // first call inside this request triggers `load_many`; every
195        // subsequent call with the same key (e.g. another invoice in
196        // the same batch) hits the request-scoped cache.
197        match ctx.session.get(CustomerForOrg(ctx.subject.org_id)).await {
198            FactLoadResult::Found(Some(customer_id)) if customer_id == ctx.resource.customer_id => {
199                ctx.grant("subject's supplier org bills under the invoice's customer")
200            }
201            _ => ctx.deny("subject's supplier org does not bill under the invoice's customer"),
202        }
203    }
Source

pub async fn get_many<K>(&self, keys: &[K]) -> Vec<FactLoadResult<K::Value>>
where K: FactKey,

Loads facts through the session cache.

Results preserve input order and duplicate keys. Missing cache entries are deduplicated before they are loaded, then chunked according to the source’s FactSource::max_batch_size hint.

Trait Implementations§

Source§

impl Clone for EvaluationSession

Source§

fn clone(&self) -> EvaluationSession

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 Default for EvaluationSession

Source§

fn default() -> EvaluationSession

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

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

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more