axum/axum-macros/src/from_ref.rs
David Pedersen 9c0a89cd09
Add #[derive(FromRef)] (#1430)
* add `#[derive(FromRef)]`

* tests

* don't support skipping fields

probably wouldn't work at all since the whole state likely needs `Clone`

* UI tests

* changelog

* changelog link

* revert hello-world example, used for testing

* Re-export `#[derive(FromRef)]`

* Don't need to return `Result`

* use `collect` instead of quoting the iterator

* Mention it in axum's changelog
2022-10-10 18:40:14 +00:00

39 lines
994 B
Rust

use proc_macro2::{Ident, TokenStream};
use quote::quote_spanned;
use syn::{spanned::Spanned, Field, ItemStruct};
pub(crate) fn expand(item: ItemStruct) -> TokenStream {
item.fields
.iter()
.enumerate()
.map(|(idx, field)| expand_field(&item.ident, idx, field))
.collect()
}
fn expand_field(state: &Ident, idx: usize, field: &Field) -> TokenStream {
let field_ty = &field.ty;
let span = field.ty.span();
let body = if let Some(field_ident) = &field.ident {
quote_spanned! {span=> state.#field_ident.clone() }
} else {
let idx = syn::Index {
index: idx as _,
span: field.span(),
};
quote_spanned! {span=> state.#idx.clone() }
};
quote_spanned! {span=>
impl ::axum::extract::FromRef<#state> for #field_ty {
fn from_ref(state: &#state) -> Self {
#body
}
}
}
}
#[test]
fn ui() {
crate::run_ui_tests("from_ref");
}