Skip to content

Commit eadb243

Browse files
Merge pull request #6 from Artem-Romanenia/features/enum-to-literal
Features/enum to literal
2 parents b8844aa + 2924f80 commit eadb243

File tree

12 files changed

+1740
-998
lines changed

12 files changed

+1740
-998
lines changed

README.md

Lines changed: 269 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ And here's the code that `o2o` generates (from here on, generated code is produc
120120
- [Traits and `o2o` *trait instructions*](#traits-and-o2o-trait-instructions)
121121
- [The (not so big) Problem](#the-not-so-big-problem)
122122
- [Inline expressions](#inline-expressions)
123-
- [Examples](#examples)
123+
- [Struct Examples](#struct-examples)
124124
- [Different member name](#different-member-name)
125125
- [Different field type](#different-field-type)
126126
- [Nested structs](#nested-structs)
@@ -133,14 +133,20 @@ And here's the code that `o2o` generates (from here on, generated code is produc
133133
- [Flatened children](#flatened-children)
134134
- [Tuple structs](#tuple-structs)
135135
- [Tuples](#tuples)
136-
- [Struct kind hints](#struct-kind-hints)
136+
- [Type hints](#type-hints)
137137
- [Generics](#generics)
138138
- [Where clauses](#where-clauses)
139139
- [Mapping to multiple structs](#mapping-to-multiple-structs)
140140
- [Avoiding proc macro attribute name collisions (alternative instruction syntax)](#avoiding-proc-macro-attribute-name-collisions-alternative-instruction-syntax)
141141
- [Additional o2o instruction available via `#[o2o(...)]` syntax](#additional-o2o-instruction-available-via-o2o-syntax)
142142
- [Primitive type conversions](#primitive-type-conversions)
143143
- [Repeat instructions](#repeat-instructions)
144+
- [Enum Examples](#enum-examples)
145+
- [Different variant name](#different-variant-name)
146+
- [Mapping to primitive types](#mapping-to-primitive-types)
147+
- [Using literals](#using-literals)
148+
- [Using patterns](#using-patterns)
149+
- [Using literals and patterns together](#using-literals-and-patterns-together)
144150
- [Contributions](#contributions)
145151
- [License](#license)
146152

@@ -152,7 +158,7 @@ To let o2o know what traits you want implemented, you have to use type-level `o2
152158
struct Entity { }
153159

154160
#[derive(o2o::o2o)]
155-
#[from_ref(Entity)] // This tells o2o to generate 'From<&Person> for PersonDto' implementation
161+
#[from_ref(Entity)] // This tells o2o to generate 'From<&Entity> for EntityDto' implementation
156162
struct EntityDto { }
157163
```
158164

@@ -247,7 +253,7 @@ o2o has a concept of Inline Expressions, which can be passed as a parameter to s
247253
struct Entity { some_int: i32 }
248254

249255
#[derive(o2o::o2o)]
250-
#[map_owned(Entity)] // tells o2o to implement 'From<Person> for PersonDto' and 'Into<Person> for PersonDto'
256+
#[map_owned(Entity)] // tells o2o to implement 'From<Entity> for EntityDto' and 'Into<Entity> for EntityDto'
251257
struct EntityDto {
252258
#[from(~ * 2)] // Let's say for whatever reason we want to multiply 'some_int' by 2 when converting from Entity
253259
#[into(~ / 2)] // And divide back by 2 when converting into it
@@ -311,7 +317,7 @@ Obviously, you can use `~` for inline expressions that are passed only to member
311317

312318
So finally, let's look at some examples.
313319

314-
## Examples
320+
## Struct Examples
315321

316322
### Different member name
317323

@@ -1190,9 +1196,9 @@ pub struct Entity{
11901196
```
11911197
</details>
11921198

1193-
### Struct kind hints
1199+
### Type hints
11941200

1195-
By default, **o2o** will suppose that the struct on the other side is the same kind of struct that the original one is. In order to convert between named and tuple structs when you need to place instructions on a tuple side, you`ll need to use Struct Kind Hint:
1201+
By default, **o2o** will suppose that the struct on the other side is the same kind of type that the original one is. In order to convert between named and tuple structs when you need to place instructions on a tuple side, you`ll need to use Type Hint:
11961202

11971203
``` rust
11981204
use o2o::o2o;
@@ -1577,6 +1583,262 @@ struct CarDto {
15771583
```
15781584
</details>
15791585

1586+
## Enum Examples
1587+
1588+
### Different variant name
1589+
1590+
``` rust
1591+
pub enum Sort {
1592+
ASC,
1593+
DESC,
1594+
None
1595+
}
1596+
1597+
#[derive(o2o::o2o)]
1598+
#[map_owned(Sort)]
1599+
pub enum SortDto {
1600+
#[map(ASC)] Ascending,
1601+
#[map(DESC)] Descending,
1602+
None
1603+
}
1604+
```
1605+
1606+
<details>
1607+
<summary>View generated code</summary>
1608+
1609+
``` rust ignore
1610+
impl std::convert::From<Sort> for SortDto {
1611+
fn from(value: Sort) -> SortDto {
1612+
match value {
1613+
Sort::ASC => SortDto::Ascending,
1614+
Sort::DESC => SortDto::Descending,
1615+
Sort::None => SortDto::None,
1616+
}
1617+
}
1618+
}
1619+
impl std::convert::Into<Sort> for SortDto {
1620+
fn into(self) -> Sort {
1621+
match self {
1622+
SortDto::Ascending => Sort::ASC,
1623+
SortDto::Descending => Sort::DESC,
1624+
SortDto::None => Sort::None,
1625+
}
1626+
}
1627+
}
1628+
```
1629+
</details>
1630+
1631+
### Mapping to primitive types
1632+
1633+
#### Using literals
1634+
1635+
Literals can be used to produce both `From` and `Into` implementations:
1636+
1637+
```rust
1638+
#[derive(o2o::o2o)]
1639+
#[map_owned(i32| _ => panic!("Not supported"))]
1640+
enum HttpStatus {
1641+
#[literal(200)]Ok,
1642+
#[literal(201)]Created,
1643+
#[literal(401)]Unauthorized,
1644+
#[literal(403)]Forbidden,
1645+
#[literal(404)]NotFound,
1646+
#[literal(500)]InternalError
1647+
}
1648+
1649+
type StaticStr = &'static str;
1650+
1651+
#[derive(o2o::o2o)]
1652+
#[map_owned(StaticStr| _ => todo!())]
1653+
enum Animal {
1654+
#[literal("🐶")] Dog,
1655+
#[literal("🐱")] Cat,
1656+
#[literal("🐵")] Monkey
1657+
}
1658+
```
1659+
<details>
1660+
<summary>View generated code</summary>
1661+
1662+
``` rust ignore
1663+
impl std::convert::From<i32> for HttpStatus {
1664+
fn from(value: i32) -> HttpStatus {
1665+
match value {
1666+
200 => HttpStatus::Ok,
1667+
201 => HttpStatus::Created,
1668+
401 => HttpStatus::Unauthorized,
1669+
403 => HttpStatus::Forbidden,
1670+
404 => HttpStatus::NotFound,
1671+
500 => HttpStatus::InternalError,
1672+
_ => panic!("Not supported"),
1673+
}
1674+
}
1675+
}
1676+
impl std::convert::Into<i32> for HttpStatus {
1677+
fn into(self) -> i32 {
1678+
match self {
1679+
HttpStatus::Ok => 200,
1680+
HttpStatus::Created => 201,
1681+
HttpStatus::Unauthorized => 401,
1682+
HttpStatus::Forbidden => 403,
1683+
HttpStatus::NotFound => 404,
1684+
HttpStatus::InternalError => 500,
1685+
}
1686+
}
1687+
}
1688+
1689+
impl std::convert::From<StaticStr> for Animal {
1690+
fn from(value: StaticStr) -> Animal {
1691+
match value {
1692+
"🐶" => Animal::Dog,
1693+
"🐱" => Animal::Cat,
1694+
"🐵" => Animal::Monkey,
1695+
_ => todo!(),
1696+
}
1697+
}
1698+
}
1699+
impl std::convert::Into<StaticStr> for Animal {
1700+
fn into(self) -> StaticStr {
1701+
match self {
1702+
Animal::Dog => "🐶",
1703+
Animal::Cat => "🐱",
1704+
Animal::Monkey => "🐵",
1705+
}
1706+
}
1707+
}
1708+
```
1709+
</details>
1710+
1711+
#### Using patterns
1712+
1713+
Patterns are only used to produce `From` implementations:
1714+
1715+
```rust
1716+
#[derive(o2o::o2o)]
1717+
#[from_owned(i32| _ => panic!())]
1718+
enum HttpStatusFamily {
1719+
#[pattern(100..=199)] Information,
1720+
#[pattern(200..=299)] Success,
1721+
#[pattern(300..=399)] Redirection,
1722+
#[pattern(400..=499)] ClientError,
1723+
#[pattern(500..=599)] ServerError,
1724+
}
1725+
1726+
type StaticStr = &'static str;
1727+
1728+
#[derive(o2o::o2o)]
1729+
#[from_owned(StaticStr| _ => todo!())]
1730+
enum AnimalKind {
1731+
#[pattern("🐶" | "🐱" | "🐵")]
1732+
Mammal,
1733+
1734+
#[pattern("🐟")]
1735+
Fish,
1736+
1737+
#[pattern("🐛" | "🐜")]
1738+
Insect
1739+
}
1740+
```
1741+
<details>
1742+
<summary>View generated code</summary>
1743+
1744+
``` rust ignore
1745+
impl std::convert::From<i32> for HttpStatusFamily {
1746+
fn from(value: i32) -> HttpStatusFamily {
1747+
match value {
1748+
100..=199 => HttpStatusFamily::Information,
1749+
200..=299 => HttpStatusFamily::Success,
1750+
300..=399 => HttpStatusFamily::Redirection,
1751+
400..=499 => HttpStatusFamily::ClientError,
1752+
500..=599 => HttpStatusFamily::ServerError,
1753+
_ => panic!(),
1754+
}
1755+
}
1756+
}
1757+
1758+
impl std::convert::From<StaticStr> for AnimalKind {
1759+
fn from(value: StaticStr) -> AnimalKind {
1760+
match value {
1761+
"🐶" | "🐱" | "🐵" => AnimalKind::Mammal,
1762+
"🐟" => AnimalKind::Fish,
1763+
"🐛" | "🐜" => AnimalKind::Insect,
1764+
_ => todo!(),
1765+
}
1766+
}
1767+
}
1768+
```
1769+
</details>
1770+
1771+
#### Using literals and patterns together
1772+
1773+
```rust
1774+
#[derive(o2o::o2o)]
1775+
#[map_owned(i32)]
1776+
enum HttpStatus {
1777+
#[literal(200)] Ok,
1778+
#[literal(404)] NotFound,
1779+
#[literal(500)] InternalError,
1780+
#[pattern(_)] #[into({f0})] Other(#[from(@)] i32)
1781+
}
1782+
1783+
type StaticStr = &'static str;
1784+
1785+
#[derive(o2o::o2o)]
1786+
#[map_owned(StaticStr)]
1787+
enum Animal {
1788+
#[literal("🐶")] Dog,
1789+
#[literal("🐱")] Cat,
1790+
#[literal("🐵")] Monkey,
1791+
#[pattern(_)] #[into({name})] Other{ #[from(@)] name: StaticStr }
1792+
}
1793+
```
1794+
<details>
1795+
<summary>View generated code</summary>
1796+
1797+
``` rust ignore
1798+
impl std::convert::From<i32> for HttpStatus {
1799+
fn from(value: i32) -> HttpStatus {
1800+
match value {
1801+
200 => HttpStatus::Ok,
1802+
404 => HttpStatus::NotFound,
1803+
500 => HttpStatus::InternalError,
1804+
_ => HttpStatus::Other(value),
1805+
}
1806+
}
1807+
}
1808+
impl std::convert::Into<i32> for HttpStatus {
1809+
fn into(self) -> i32 {
1810+
match self {
1811+
HttpStatus::Ok => 200,
1812+
HttpStatus::NotFound => 404,
1813+
HttpStatus::InternalError => 500,
1814+
HttpStatus::Other(f0) => f0,
1815+
}
1816+
}
1817+
}
1818+
1819+
impl std::convert::From<StaticStr> for Animal {
1820+
fn from(value: StaticStr) -> Animal {
1821+
match value {
1822+
"🐶" => Animal::Dog,
1823+
"🐱" => Animal::Cat,
1824+
"🐵" => Animal::Monkey,
1825+
_ => Animal::Other { name: value },
1826+
}
1827+
}
1828+
}
1829+
impl std::convert::Into<StaticStr> for Animal {
1830+
fn into(self) -> StaticStr {
1831+
match self {
1832+
Animal::Dog => "🐶",
1833+
Animal::Cat => "🐱",
1834+
Animal::Monkey => "🐵",
1835+
Animal::Other { name } => name,
1836+
}
1837+
}
1838+
}
1839+
```
1840+
</details>
1841+
15801842
## Contributions
15811843

15821844
All issues, questions, pull requests are extremely welcome.

o2o-impl/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ quote = "1.0.0"
1414

1515
[dev-dependencies]
1616
criterion = "0.4"
17+
test-case = "*"
1718

1819
[[bench]]
1920
name = "o2o_benchmarks"

o2o-impl/src/ast.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(crate) struct Struct<'a> {
1515

1616
impl<'a> Struct<'a> {
1717
pub fn from_syn(node: &'a DeriveInput, data: &'a DataStruct) -> Result<Self> {
18-
let (attrs, bark) = attr::get_struct_attrs(&node.attrs)?;
18+
let (attrs, bark) = attr::get_data_type_attrs(&node.attrs)?;
1919
let fields = Field::multiple_from_syn(&data.fields, bark)?;
2020
Ok(Struct {
2121
attrs,
@@ -65,7 +65,7 @@ impl<'a> Field {
6565

6666
fn from_syn(i: usize, node: &'a syn::Field, bark: bool) -> Result<Self> {
6767
Ok(Field {
68-
attrs: attr::get_field_attrs(SynDataTypeMember::Field(node), bark)?,
68+
attrs: attr::get_member_attrs(SynDataTypeMember::Field(node), bark)?,
6969
idx: i,
7070
member: node.ident.clone().map(Member::Named).unwrap_or_else(|| {
7171
Member::Unnamed(Index {
@@ -86,7 +86,7 @@ pub(crate) struct Enum<'a> {
8686

8787
impl<'a> Enum<'a> {
8888
pub fn from_syn(node: &'a DeriveInput, data: &'a DataEnum) -> Result<Self> {
89-
let (attrs, bark) = attr::get_struct_attrs(&node.attrs)?;
89+
let (attrs, bark) = attr::get_data_type_attrs(&node.attrs)?;
9090
let variants = Variant::multiple_from_syn(&data.variants, bark)?;
9191
Ok(Enum {
9292
attrs,
@@ -137,7 +137,7 @@ impl<'a> Variant {
137137
fn from_syn(i: usize, variant: &'a syn::Variant, bark: bool) -> Result<Self> {
138138
let fields = Field::multiple_from_syn(&variant.fields, bark)?;
139139
Ok(Variant {
140-
attrs: attr::get_field_attrs(SynDataTypeMember::Variant(variant), bark)?,
140+
attrs: attr::get_member_attrs(SynDataTypeMember::Variant(variant), bark)?,
141141
ident: variant.ident.clone(),
142142
_idx: i,
143143
fields,

0 commit comments

Comments
 (0)