Skip to content

Commit

Permalink
Use default attribute when constructing skipped values
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Apr 10, 2024
1 parent 0e40e7c commit 79d04b6
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 78 deletions.
11 changes: 7 additions & 4 deletions crates/musli-macros/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use syn::Token;
use crate::expander::{Result, TagMethod};
use crate::internals::apply;
use crate::internals::attr::{EnumTag, EnumTagging, Packing};
use crate::internals::build::{Body, Build, BuildData, Enum, Field, FieldSkip, Variant};
use crate::internals::build::{Body, Build, BuildData, Enum, Field, Variant};
use crate::internals::tokens::Tokens;

struct Ctxt<'a> {
Expand Down Expand Up @@ -765,11 +765,14 @@ fn decode_tagged(
let decode_path = &f.decode_path.1;

let expr = match &f.skip {
Some(FieldSkip::Default(span)) => {
Some(span) => {
let ty = f.ty;
syn::Expr::Verbatim(quote_spanned!(*span => #default_function::<#ty>()))

match &f.default_attr {
Some((_, Some(path))) => syn::Expr::Verbatim(quote_spanned!(*span => #path())),
_ => syn::Expr::Verbatim(quote_spanned!(*span => #default_function::<#ty>())),
}
}
Some(FieldSkip::Expr(expr)) => expr.clone(),
None => {
let formatted_tag = match &st.name_format_with {
Some((_, path)) => quote!(&#path(&#tag)),
Expand Down
14 changes: 3 additions & 11 deletions crates/musli-macros/src/internals/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ use crate::expander::TagMethod;
use crate::internals::ATTR;
use crate::internals::{Ctxt, Mode};

use super::build::FieldSkip;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum Only {
Encode,
Expand Down Expand Up @@ -575,7 +573,7 @@ layer! {
/// Use a default value for the field if it's not available.
is_default: Option<syn::Path>,
/// Use a default value for the field if it's not available.
skip: FieldSkip,
skip: (),
/// Use the alternate TraceDecode for the field.
trace: (),
/// Use the alternate EncodeBytes for the field.
Expand Down Expand Up @@ -706,15 +704,9 @@ pub(crate) fn field_attrs(cx: &Ctxt, attrs: &[syn::Attribute]) -> Field {
return Ok(());
}

// parse #[musli(skip [= <path>])]
// parse #[musli(skip)]
if meta.path.is_ident("skip") {
let skip = if meta.input.parse::<Option<Token![=]>>()?.is_some() {
FieldSkip::Expr(meta.input.parse()?)
} else {
FieldSkip::Default(meta.path.span())
};

new.skip.push((meta.path.span(), skip));
new.skip.push((meta.path.span(), ()));
return Ok(());
}

Expand Down
18 changes: 5 additions & 13 deletions crates/musli-macros/src/internals/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,26 +163,18 @@ pub(crate) struct Variant<'a> {
pub(crate) patterns: Punctuated<syn::FieldPat, Token![,]>,
}

/// Field skip configuration.
pub(crate) enum FieldSkip {
/// Skip with a default value.
Default(Span),
/// Skip with an expression.
Expr(syn::Expr),
}

pub(crate) struct Field<'a> {
pub(crate) span: Span,
pub(crate) index: usize,
pub(crate) encode_path: (Span, syn::Path),
pub(crate) decode_path: (Span, syn::Path),
pub(crate) tag: syn::Expr,
/// Skip field entirely and always initialize with the specified expresion,
/// or default value through `default_attr`.
pub(crate) skip: Option<Span>,
pub(crate) skip_encoding_if: Option<&'a (Span, syn::Path)>,
/// Fill with default value, if missing.
pub(crate) default_attr: Option<(Span, Option<&'a syn::Path>)>,
/// Skip field entirely and always initialize with the specified expresion,
/// or default value if none is specified.
pub(crate) skip: Option<&'a FieldSkip>,
pub(crate) self_access: syn::Expr,
pub(crate) member: syn::Member,
pub(crate) packing: Packing,
Expand Down Expand Up @@ -419,12 +411,12 @@ fn setup_field<'a>(
let decode_path = data.attr.decode_path_expanded(mode, data.span);
let (tag, tag_method) = data.expand_tag(e, mode, default_field)?;
tag_methods.insert(data.span, tag_method);
let skip = data.attr.skip(mode).map(|&(s, ())| s);
let skip_encoding_if = data.attr.skip_encoding_if(mode);
let default_attr = data
.attr
.is_default(mode)
.map(|(s, path)| (*s, path.as_ref()));
let skip = data.attr.skip(mode).map(|(_, skip)| skip);

let member = match data.ident {
Some(ident) => syn::Member::Named(ident.clone()),
Expand Down Expand Up @@ -508,9 +500,9 @@ fn setup_field<'a>(
encode_path,
decode_path,
tag,
skip,
skip_encoding_if,
default_attr,
skip,
self_access,
member,
packing,
Expand Down
30 changes: 25 additions & 5 deletions crates/musli/src/derives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,10 +533,14 @@
//! struct Struct {
//! #[musli(rename = "other")]
//! something: String,
//! #[musli(skip = 42)]
//! #[musli(skip, default = default_field)]
//! skipped_field: u32,
//! }
//!
//! fn default_field() -> u32 {
//! 42
//! }
//!
//! #[derive(Encode, Decode)]
//! #[musli(default_field = "name")]
//! enum Enum {
Expand All @@ -563,17 +567,27 @@
//! name: String,
//! #[musli(skip)]
//! age: Option<u32>,
//! #[musli(skip = Some(String::from("Earth")))]
//! #[musli(skip, default = default_country)]
//! country: Option<String>,
//! }
//!
//! fn default_country() -> Option<String> {
//! Some(String::from("Earth"))
//! }
//! ```
//!
//! <br>
//!
//! #### `#[musli(default)]`
//! #### `#[musli(default [= <path>])]`
//!
//! This constructs the field using [`Default::default`] in case it's not
//! available. This is only used when a field is missing during decoding.
//! When a field is absent or disabled with `#[musli(skip)]`, this attribute
//! specifies that a default value should be used instead.
//!
//! If `#[musli(default)]` is specified, the default value is constructed using
//! [`Default::default`].
//!
//! If `#[musli(default = <path>)]` is specified, the default value is
//! constructed by calling the function at `<path>`.
//!
//! ```
//! use musli::{Encode, Decode};
Expand All @@ -585,11 +599,17 @@
//! age: Option<u32>,
//! #[musli(default = default_height)]
//! height: Option<u32>,
//! #[musli(skip, default = default_meaning)]
//! meaning: u32,
//! }
//!
//! fn default_height() -> Option<u32> {
//! Some(180)
//! }
//!
//! fn default_meaning() -> u32 {
//! 42
//! }
//! ```
//!
//! <br>
Expand Down
Loading

0 comments on commit 79d04b6

Please sign in to comment.