Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 60 additions & 73 deletions tests/tests/ui/not_valuable.stderr
Original file line number Diff line number Diff line change
@@ -1,86 +1,73 @@
error[E0277]: the trait bound `S: Valuable` is not satisfied
--> tests/ui/not_valuable.rs:7:8
error[E0599]: the method `as_value` exists for enum `Option<S>`, but its trait bounds were not satisfied
--> tests/ui/not_valuable.rs:5:10
|
3 | struct S;
| -------- doesn't satisfy `S: Valuable`
4 |
5 | #[derive(Valuable)]
| -------- required by a bound introduced by this call
6 | struct Struct {
7 | f: Option<S>,
| ^^^^^^^^^ the trait `Valuable` is not implemented for `S`
| ^^^^^^^^ method cannot be called on `Option<S>` due to unsatisfied trait bounds
|
= help: the following other types implement trait `Valuable`:
&T
&[T]
&mut T
&std::path::Path
&str
()
(T0, T1)
(T0, T1, T2)
and $N others
= note: required for `Option<S>` to implement `Valuable`
::: $RUST/core/src/option.rs
|
| pub enum Option<T> {
| ------------------ doesn't satisfy `Option<S>: Valuable`
|
= note: the following trait bounds were not satisfied:
`S: Valuable`
which is required by `Option<S>: Valuable`
note: the trait `Valuable` must be implemented
--> $WORKSPACE/valuable/src/valuable.rs
|
| pub trait Valuable {
| ^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Valuable` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `S: Valuable` is not satisfied
--> tests/ui/not_valuable.rs:11:14
error[E0599]: the method `as_value` exists for enum `Option<S>`, but its trait bounds were not satisfied
--> tests/ui/not_valuable.rs:10:10
|
3 | struct S;
| -------- doesn't satisfy `S: Valuable`
...
10 | #[derive(Valuable)]
| -------- required by a bound introduced by this call
11 | struct Tuple(Option<S>);
| ^^^^^^^^^ the trait `Valuable` is not implemented for `S`
| ^^^^^^^^ method cannot be called on `Option<S>` due to unsatisfied trait bounds
|
= help: the following other types implement trait `Valuable`:
&T
&[T]
&mut T
&std::path::Path
&str
()
(T0, T1)
(T0, T1, T2)
and $N others
= note: required for `Option<S>` to implement `Valuable`

error[E0277]: the trait bound `S: Valuable` is not satisfied
--> tests/ui/not_valuable.rs:15:25
::: $RUST/core/src/option.rs
|
13 | #[derive(Valuable)]
| -------- required by a bound introduced by this call
14 | enum Enum {
15 | Struct { f: Option<S> },
| ^ the trait `Valuable` is not implemented for `S`
| pub enum Option<T> {
| ------------------ doesn't satisfy `Option<S>: Valuable`
|
= help: the following other types implement trait `Valuable`:
&T
&[T]
&mut T
&std::path::Path
&str
()
(T0, T1)
(T0, T1, T2)
and $N others
= note: required for `Option<S>` to implement `Valuable`
= note: 1 redundant requirement hidden
= note: required for `&Option<S>` to implement `Valuable`
= note: the following trait bounds were not satisfied:
`S: Valuable`
which is required by `Option<S>: Valuable`
note: the trait `Valuable` must be implemented
--> $WORKSPACE/valuable/src/valuable.rs
|
| pub trait Valuable {
| ^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Valuable` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `S: Valuable` is not satisfied
--> tests/ui/not_valuable.rs:16:19
error[E0599]: the method `as_value` exists for reference `&Option<S>`, but its trait bounds were not satisfied
--> tests/ui/not_valuable.rs:13:10
|
13 | #[derive(Valuable)]
| -------- required by a bound introduced by this call
3 | struct S;
| -------- doesn't satisfy `S: Valuable`
...
16 | Tuple(Option<S>),
| ^ the trait `Valuable` is not implemented for `S`
13 | #[derive(Valuable)]
| ^^^^^^^^ method cannot be called on `&Option<S>` due to unsatisfied trait bounds
|
::: $RUST/core/src/option.rs
|
| pub enum Option<T> {
| ------------------ doesn't satisfy `Option<S>: Valuable`
|
= note: the following trait bounds were not satisfied:
`S: Valuable`
which is required by `Option<S>: Valuable`
`Option<S>: Valuable`
which is required by `&Option<S>: Valuable`
note: the trait `Valuable` must be implemented
--> $WORKSPACE/valuable/src/valuable.rs
|
= help: the following other types implement trait `Valuable`:
&T
&[T]
&mut T
&std::path::Path
&str
()
(T0, T1)
(T0, T1, T2)
and $N others
= note: required for `Option<S>` to implement `Valuable`
= note: 1 redundant requirement hidden
= note: required for `&Option<S>` to implement `Valuable`
| pub trait Valuable {
| ^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Valuable` (in Nightly builds, run with -Z macro-backtrace for more info)
79 changes: 79 additions & 0 deletions valuable-derive/examples/comprehensive_demo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use valuable::Valuable;

/// Stack copy: bool -> bool
fn invert_flag(active: &bool) -> bool {
!*active
}

/// Heap allocation: u64 -> String
fn format_id(id: &u64) -> String {
format!("ID-{:06}", id)
}

/// Complex transformation: Vec<String> -> Box<[String]>
fn uppercase_list(items: &[String]) -> Box<[String]> {
items
.iter()
.map(|s| s.to_uppercase())
.collect::<Vec<_>>()
.into_boxed_slice()
}

#[derive(Valuable, Debug)]
struct Example {
id: u64,

#[valuable(with = "invert_flag")]
active: bool,

#[valuable(with = "format_id")]
user_id: u64,

#[valuable(with = "uppercase_list")]
tags: Vec<String>,

#[valuable(skip)]
#[allow(dead_code)]
secret: String,
}

fn main() {
let example = Example {
id: 42,
active: false,
user_id: 12345,
tags: vec!["admin".to_string(), "user".to_string()],
secret: "hidden".to_string(),
};

println!("Debug: {example:?}");

struct TestVisitor {
fields: Vec<(String, String)>,
}

impl valuable::Visit for TestVisitor {
fn visit_value(&mut self, _value: valuable::Value<'_>) {}

fn visit_named_fields(&mut self, named_values: &valuable::NamedValues<'_>) {
for (field, value) in named_values {
self.fields
.push((field.name().to_string(), format!("{value:?}")));
}
}

fn visit_unnamed_fields(&mut self, values: &[valuable::Value<'_>]) {
for (i, value) in values.iter().enumerate() {
self.fields.push((i.to_string(), format!("{value:?}")));
}
}
}

let mut visitor = TestVisitor { fields: Vec::new() };
example.visit(&mut visitor);

println!("Valuable fields:");
for (name, value) in visitor.fields {
println!(" {}: {}", name, value);
}
}
21 changes: 20 additions & 1 deletion valuable-derive/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ static ATTRS: &[AttrDef] = &[
// #[valuable(skip)]
AttrDef {
name: "skip",
conflicts_with: &["rename"],
conflicts_with: &["rename", "with"],
position: &[
// TODO: How do we implement Enumerable::variant and Valuable::as_value if a variant is skipped?
// Position::Variant,
Expand All @@ -42,12 +42,20 @@ static ATTRS: &[AttrDef] = &[
],
style: &[MetaStyle::Ident],
},
// #[valuable(with = "...")]
AttrDef {
name: "with",
conflicts_with: &["skip"],
position: &[Position::NamedField, Position::UnnamedField],
style: &[MetaStyle::NameValue],
},
];

pub(crate) struct Attrs {
rename: Option<(syn::MetaNameValue, syn::LitStr)>,
transparent: Option<Span>,
skip: Option<Span>,
with: Option<(syn::MetaNameValue, syn::LitStr)>,
}

impl Attrs {
Expand All @@ -65,12 +73,20 @@ impl Attrs {
pub(crate) fn skip(&self) -> bool {
self.skip.is_some()
}

pub(crate) fn with(&self) -> Option<syn::Expr> {
self.with.as_ref().map(|(_, lit_str)| {
let path_str = lit_str.value();
syn::parse_str(&path_str).expect("failed to parse with function path")
})
}
}

pub(crate) fn parse_attrs(cx: &Context, attrs: &[syn::Attribute], pos: Position) -> Attrs {
let mut rename = None;
let mut transparent = None;
let mut skip = None;
let mut with = None;

let attrs = filter_attrs(cx, attrs, pos);
for (def, meta) in &attrs {
Expand Down Expand Up @@ -104,6 +120,8 @@ pub(crate) fn parse_attrs(cx: &Context, attrs: &[syn::Attribute], pos: Position)
"transparent" => transparent = Some(meta.span()),
// #[valuable(skip)]
"skip" => skip = Some(meta.span()),
// #[valuable(with = "...")]
"with" => lit_str!(with),

_ => unreachable!("{}", def.name),
}
Expand All @@ -113,6 +131,7 @@ pub(crate) fn parse_attrs(cx: &Context, attrs: &[syn::Attribute], pos: Position)
rename,
transparent,
skip,
with,
}
}

Expand Down
Loading
Loading