mirror of
https://github.com/tokio-rs/axum.git
synced 2024-11-22 07:08:16 +01:00
parent
64960bb19c
commit
7d58d49817
5 changed files with 84 additions and 2 deletions
|
@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- None.
|
- **added:** Add `#[from_ref(skip)]` to skip implementing `FromRef` for individual fields ([#1537])
|
||||||
|
|
||||||
|
[#1537]: https://github.com/tokio-rs/axum/pull/1537
|
||||||
|
|
||||||
# 0.3.0-rc.2 (8. November, 2022)
|
# 0.3.0-rc.2 (8. November, 2022)
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,21 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn combine_unary_attribute<K>(a: &mut Option<K>, b: Option<K>) -> syn::Result<()>
|
||||||
|
where
|
||||||
|
K: ToTokens,
|
||||||
|
{
|
||||||
|
if let Some(kw) = b {
|
||||||
|
if a.is_some() {
|
||||||
|
let kw_name = std::any::type_name::<K>().split("::").last().unwrap();
|
||||||
|
let msg = format!("`{}` specified more than once", kw_name);
|
||||||
|
return Err(syn::Error::new_spanned(kw, msg));
|
||||||
|
}
|
||||||
|
*a = Some(kw);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn second<T, K>(tuple: (T, K)) -> K {
|
pub(crate) fn second<T, K>(tuple: (T, K)) -> K {
|
||||||
tuple.1
|
tuple.1
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::{Ident, TokenStream};
|
||||||
use quote::quote_spanned;
|
use quote::quote_spanned;
|
||||||
use syn::{spanned::Spanned, Field, ItemStruct};
|
use syn::{
|
||||||
|
parse::{Parse, ParseStream},
|
||||||
|
spanned::Spanned,
|
||||||
|
Field, ItemStruct, Token,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::attr_parsing::{combine_unary_attribute, parse_attrs, Combine};
|
||||||
|
|
||||||
pub(crate) fn expand(item: ItemStruct) -> TokenStream {
|
pub(crate) fn expand(item: ItemStruct) -> TokenStream {
|
||||||
item.fields
|
item.fields
|
||||||
|
@ -11,6 +17,15 @@ pub(crate) fn expand(item: ItemStruct) -> TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_field(state: &Ident, idx: usize, field: &Field) -> TokenStream {
|
fn expand_field(state: &Ident, idx: usize, field: &Field) -> TokenStream {
|
||||||
|
let FieldAttrs { skip } = match parse_attrs("from_ref", &field.attrs) {
|
||||||
|
Ok(attrs) => attrs,
|
||||||
|
Err(err) => return err.into_compile_error(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if skip.is_some() {
|
||||||
|
return TokenStream::default();
|
||||||
|
}
|
||||||
|
|
||||||
let field_ty = &field.ty;
|
let field_ty = &field.ty;
|
||||||
let span = field.ty.span();
|
let span = field.ty.span();
|
||||||
|
|
||||||
|
@ -33,6 +48,42 @@ fn expand_field(state: &Ident, idx: usize, field: &Field) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod kw {
|
||||||
|
syn::custom_keyword!(skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(super) struct FieldAttrs {
|
||||||
|
pub(super) skip: Option<kw::skip>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for FieldAttrs {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let mut skip = None;
|
||||||
|
|
||||||
|
while !input.is_empty() {
|
||||||
|
let lh = input.lookahead1();
|
||||||
|
if lh.peek(kw::skip) {
|
||||||
|
skip = Some(input.parse()?);
|
||||||
|
} else {
|
||||||
|
return Err(lh.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = input.parse::<Token![,]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { skip })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Combine for FieldAttrs {
|
||||||
|
fn combine(mut self, other: Self) -> syn::Result<Self> {
|
||||||
|
let Self { skip } = other;
|
||||||
|
combine_unary_attribute(&mut self.skip, skip)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ui() {
|
fn ui() {
|
||||||
crate::run_ui_tests("from_ref");
|
crate::run_ui_tests("from_ref");
|
||||||
|
|
|
@ -589,6 +589,9 @@ pub fn derive_typed_path(input: TokenStream) -> TokenStream {
|
||||||
/// struct AppState {
|
/// struct AppState {
|
||||||
/// auth_token: AuthToken,
|
/// auth_token: AuthToken,
|
||||||
/// database_pool: DatabasePool,
|
/// database_pool: DatabasePool,
|
||||||
|
/// // fields can also be skipped
|
||||||
|
/// #[from_ref(skip)]
|
||||||
|
/// api_token: String,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // So those types can be extracted via `State`
|
/// // So those types can be extracted via `State`
|
||||||
|
@ -601,6 +604,7 @@ pub fn derive_typed_path(input: TokenStream) -> TokenStream {
|
||||||
/// let state = AppState {
|
/// let state = AppState {
|
||||||
/// auth_token,
|
/// auth_token,
|
||||||
/// database_pool,
|
/// database_pool,
|
||||||
|
/// api_token: "secret".to_owned(),
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// let app = Router::new()
|
/// let app = Router::new()
|
||||||
|
|
10
axum-macros/tests/from_ref/pass/skip.rs
Normal file
10
axum-macros/tests/from_ref/pass/skip.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use axum_macros::FromRef;
|
||||||
|
|
||||||
|
#[derive(Clone, FromRef)]
|
||||||
|
struct AppState {
|
||||||
|
auth_token: String,
|
||||||
|
#[from_ref(skip)]
|
||||||
|
also_string: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in a new issue