Borrowing through Axum's `FromRef` trait?

Axum provides a trait, FromRef, that it uses to allow handlers to accept state values that can be derived from the router's primary state type, rather than having to accept only values of that specific type. It's defined as

pub trait FromRef<T> {
    fn from_ref(input: &T) -> Self;
}

One example might be:

impl FromRef<AppState> for DatabasePool {
  fn from_ref(app_state: &AppState) -> DatabasePool {
    app_state.database_pool.clone()
  }
}

My question is, can I derive structs that contain references borrowed from T? For example, is there a way to implement FromRef such that I can get a DatabasePoolRef<'a> from &'a AppState? I wasn't able to get something working myself, and I half suspect that the design of the trait effectively means that the answer is no, but I thought I'd ask in case I've missed something.

Here's an example that doesn't work:

struct Foo<'a> {
    db: &'a db,
}

impl<'a> FromRef<App> for Foo<'a> {
    fn from_ref(app: &'a App) -> Self {
        Self { db: &app.db }
    }
}

This gives

error[E0308]: method not compatible with trait
  --> src/app.rs:85:5
   |
85 |     fn from_ref(app: &'a App) -> Self {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected signature `fn(&App) -> Foo<'_>`
              found signature `fn(&'a App) -> Foo<'_>`
note: the anonymous lifetime as defined here...
  --> /Users/owen/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/axum-core-0.5.0/src/extract/from_ref.rs:15:24
   |
15 |     fn from_ref(input: &T) -> Self;
   |                        ^
note: ...does not necessarily outlive the lifetime `'a` as defined here
  --> src/app.rs:84:6
   |
84 | impl<'a> FromRef<App> for Foo<'a> {
   |      ^^

The signature of the trait method means that the outer lifetime...

pub trait FromRef<T> {
    // This one --------vv
    fn from_ref(input: &'_ T) -> Self;
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // "For all input lifetimes, produce the same output type `Self`"
}

...cannot appear in the implementing type (Self).

You could...

impl<'a> FromRef<&'a App> for Foo<'a> {
    fn from_ref(app: &&'a App) -> Self {
        Self { db: &app.db }
    }
}

...but I suspect it may not work well for things that use the FromRef trait (probably it's a bound on some methods that have an owned App and take &self?).

((The capability you really have is From<&'a App> for Foo<'a>.))

It is indeed. It's called by Axum, using the provided state type, by value, and changing that would require me to vendor and modify Axum itself. It's quite probable that Axum uses its own trait for this, rather than From, for reasons that will bite me if I start trying to make that change, too.

Ah well. Prophylactic clones it is, to ensure that derived states' lifetimes are independent of the original state's lifetime - thank you!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.