Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

derive: implement #[valuable] attributes #75

Merged
merged 14 commits into from
Aug 26, 2024
130 changes: 129 additions & 1 deletion tests/tests/derive.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(feature = "derive")]
#![allow(dead_code)]

use valuable::Valuable;
use valuable::*;

use std::collections::HashMap;
use std::env;
Expand Down Expand Up @@ -66,6 +66,134 @@ fn test_derive_mut() {
}
}

#[test]
fn test_rename() {
#[derive(Valuable)]
#[valuable(rename = "A")]
struct S {
#[valuable(rename = "b")]
f: (),
}

#[derive(Valuable)]
#[valuable(rename = "C")]
enum E {
#[valuable(rename = "D")]
S {
#[valuable(rename = "e")]
f: (),
},
#[valuable(rename = "F")]
T(()),
#[valuable(rename = "G")]
U,
}

let s = Structable::definition(&S { f: () });
assert_eq!(s.name(), "A");
assert!(matches!(s.fields(), Fields::Named(f) if f[0].name() == "b"));
let e = Enumerable::definition(&E::S { f: () });
assert_eq!(e.name(), "C");
assert_eq!(e.variants()[0].name(), "D");
assert!(matches!(e.variants()[0].fields(), Fields::Named(f) if f[0].name() == "e"));
let e = Enumerable::definition(&E::T(()));
assert_eq!(e.variants()[1].name(), "F");
let e = Enumerable::definition(&E::U);
assert_eq!(e.variants()[2].name(), "G");
}

#[test]
fn test_skip_empty() {
struct NotValuable;

#[derive(Valuable)]
struct S {
#[valuable(skip)]
f: NotValuable,
}

#[derive(Valuable)]
struct T(#[valuable(skip)] NotValuable);

#[derive(Valuable)]
enum E {
S {
#[valuable(skip)]
f: NotValuable,
},
T(#[valuable(skip)] NotValuable),
}

let s = Structable::definition(&S { f: NotValuable });
assert!(matches!(s.fields(), Fields::Named(f) if f.is_empty()));
let s = Structable::definition(&T(NotValuable));
assert!(matches!(s.fields(), Fields::Unnamed(f) if *f == 0));
let e = Enumerable::definition(&E::S { f: NotValuable });
assert_eq!(e.variants().len(), 2);
assert!(matches!(e.variants()[0].fields(), Fields::Named(f) if f.is_empty()));
assert!(matches!(e.variants()[1].fields(), Fields::Unnamed(f) if *f == 0));
}

#[test]
fn test_skip() {
struct NotValuable;

#[derive(Valuable)]
struct S {
f1: (),
#[valuable(skip)]
f2: NotValuable,
f3: (),
}

#[derive(Valuable)]
struct T((), #[valuable(skip)] NotValuable, ());

#[derive(Valuable)]
enum E {
S {
f1: (),
#[valuable(skip)]
f2: NotValuable,
f3: (),
},
T((), #[valuable(skip)] NotValuable, ()),
}

let s = Structable::definition(&S {
f1: (),
f2: NotValuable,
f3: (),
});
assert!(matches!(s.fields(), Fields::Named(f) if f.len() == 2));
let s = Structable::definition(&T((), NotValuable, ()));
assert!(matches!(s.fields(), Fields::Unnamed(f) if *f == 2));
let e = Enumerable::definition(&E::S {
f1: (),
f2: NotValuable,
f3: (),
});
assert_eq!(e.variants().len(), 2);
assert!(matches!(e.variants()[0].fields(), Fields::Named(f) if f.len() == 2));
assert!(matches!(e.variants()[1].fields(), Fields::Unnamed(f) if *f == 2));
}

#[test]
fn test_transparent() {
#[derive(Valuable)]
#[valuable(transparent)]
struct S {
f: u8,
}

#[derive(Valuable)]
#[valuable(transparent)]
struct T(char);

assert!(matches!(Valuable::as_value(&S { f: 0 }), Value::U8(0)));
assert!(matches!(Valuable::as_value(&T('a')), Value::Char('a')));
}

#[rustversion::attr(not(stable), ignore)]
#[test]
fn ui() {
Expand Down
8 changes: 4 additions & 4 deletions tests/tests/ui/not_valuable.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ error[E0277]: the trait bound `S: Valuable` is not satisfied
= note: required for `Option<S>` to implement `Valuable`

error[E0277]: the trait bound `S: Valuable` is not satisfied
--> tests/ui/not_valuable.rs:15:17
--> tests/ui/not_valuable.rs:15:25
|
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`, which is required by `&Option<S>: Valuable`
| ^ the trait `Valuable` is not implemented for `S`, which is required by `&Option<S>: Valuable`
|
= help: the following other types implement trait `Valuable`:
&T
Expand All @@ -63,13 +63,13 @@ error[E0277]: the trait bound `S: Valuable` is not satisfied
= note: required for `&Option<S>` to implement `Valuable`

error[E0277]: the trait bound `S: Valuable` is not satisfied
--> tests/ui/not_valuable.rs:16:11
--> tests/ui/not_valuable.rs:16:19
|
13 | #[derive(Valuable)]
| -------- required by a bound introduced by this call
...
16 | Tuple(Option<S>),
| ^^^^^^^^^ the trait `Valuable` is not implemented for `S`, which is required by `&Option<S>: Valuable`
| ^ the trait `Valuable` is not implemented for `S`, which is required by `&Option<S>: Valuable`
|
= help: the following other types implement trait `Valuable`:
&T
Expand Down
53 changes: 53 additions & 0 deletions tests/tests/ui/unexpected.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use valuable::*;

#[derive(Valuable)]
struct Rename1 {
#[valuable(rename = b)]
f: (),
}
#[derive(Valuable)]
struct Rename2 {
#[valuable(rename = 'b')]
f: (),
}

#[derive(Valuable)]
struct Transparent1 {
#[valuable(transparent)]
f: (),
}
#[derive(Valuable)]
#[valuable(transparent)]
enum Transparent2 {
V(()),
}
#[derive(Valuable)]
#[valuable(transparent)]
struct Transparent3 {
f1: (),
f2: (),
}
#[derive(Valuable)]
#[valuable(transparent, rename = "a")]
struct Transparent4 {
f: (),
}

#[derive(Valuable)]
#[valuable(skip)]
struct Skip1 {
f: (),
}
#[derive(Valuable)]
#[valuable(skip)]
enum Skip2 {
#[valuable(skip)]
V(()),
}
#[derive(Valuable)]
struct Skip3 {
#[valuable(skip, rename = "a")]
f: (),
}

fn main() {}
63 changes: 63 additions & 0 deletions tests/tests/ui/unexpected.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
error: expected string literal
--> tests/ui/unexpected.rs:5:25
|
5 | #[valuable(rename = b)]
| ^

error: expected string literal
--> tests/ui/unexpected.rs:10:25
|
10 | #[valuable(rename = 'b')]
| ^^^

error: #[valuable(transparent)] may only be used on structs
--> tests/ui/unexpected.rs:16:16
|
16 | #[valuable(transparent)]
| ^^^^^^^^^^^

error: #[valuable(transparent)] may only be used on structs
--> tests/ui/unexpected.rs:20:12
|
20 | #[valuable(transparent)]
| ^^^^^^^^^^^

error: #[valuable(transparent)] struct needs exactly one field, but has 2
--> tests/ui/unexpected.rs:25:1
|
25 | / #[valuable(transparent)]
26 | | struct Transparent3 {
27 | | f1: (),
28 | | f2: (),
29 | | }
| |_^

error: #[valuable(transparent)] may not be used together with #[valuable(rename)]
--> tests/ui/unexpected.rs:31:25
|
31 | #[valuable(transparent, rename = "a")]
| ^^^^^^

error: #[valuable(skip)] may only be used on fields
--> tests/ui/unexpected.rs:37:12
|
37 | #[valuable(skip)]
| ^^^^

error: #[valuable(skip)] may only be used on fields
--> tests/ui/unexpected.rs:42:12
|
42 | #[valuable(skip)]
| ^^^^

error: #[valuable(skip)] may only be used on fields
--> tests/ui/unexpected.rs:44:16
|
44 | #[valuable(skip)]
| ^^^^

error: #[valuable(skip)] may not be used together with #[valuable(rename)]
--> tests/ui/unexpected.rs:49:22
|
49 | #[valuable(skip, rename = "a")]
| ^^^^^^
Loading