Skip to content

Commit a459ea3

Browse files
authored
Merge pull request #590 from joshuachp/push-nsytqoommonn
feat(derive): add rename attribute to the derive macros
2 parents 5879da8 + 4beddca commit a459ea3

File tree

6 files changed

+423
-627
lines changed

6 files changed

+423
-627
lines changed

Cargo.lock

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ cfg-if = "1.0.0"
182182
chrono = "0.4.34"
183183
clap = "4.5.32"
184184
color-eyre = "0.6.3"
185+
darling = "0.23.0"
185186
eyre = "0.6.12"
186187
flate2 = "1.0.0"
187188
futures = "0.3.0"

astarte-device-sdk-derive/Cargo.toml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
# This file is part of Astarte.
22
#
3-
# Copyright 2023 SECO Mind Srl
3+
# Copyright 2023, 2026 SECO Mind Srl
44
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# SPDX-License-Identifier: Apache-2.0
518
# SPDX-License-Identifier: CC0-1.0
619

720
[package]
@@ -24,6 +37,7 @@ description = "Derive macros implementation used by Astarte Device SDK"
2437
proc-macro = true
2538

2639
[dependencies]
40+
darling.workspace = true
2741
proc-macro2.workspace = true
2842
quote.workspace = true
2943
syn = { workspace = true, features = ["full"] }

astarte-device-sdk-derive/src/case.rs

Lines changed: 44 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of Astarte.
22
//
3-
// Copyright 2023 - 2025 SECO Mind Srl
3+
// Copyright 2023-2026 SECO Mind Srl
44
//
55
// Licensed under the Apache License, Version 2.0 (the "License");
66
// you may not use this file except in compliance with the License.
@@ -16,68 +16,49 @@
1616
//
1717
// SPDX-License-Identifier: Apache-2.0
1818

19-
use std::{
20-
borrow::Cow,
21-
fmt::{self, Debug, Display},
22-
};
19+
use std::fmt::Debug;
20+
21+
use darling::FromMeta;
2322

2423
/// The different possible ways to change case of fields in a struct.
25-
#[derive(Debug, Copy, Clone, PartialEq, Default)]
24+
#[derive(Debug, Copy, Clone, PartialEq, FromMeta)]
2625
pub enum RenameRule {
27-
/// Do not rename.
28-
#[default]
29-
None,
3026
/// Rename to "lowercase" style.
31-
LowerCase,
27+
#[darling(rename = "lowercase")]
28+
Lower,
3229
/// Rename to "UPPERCASE" style.
33-
UpperCase,
30+
#[darling(rename = "UPPERCASE")]
31+
Upper,
3432
/// Rename to "PascalCase" style.
35-
PascalCase,
33+
#[darling(rename = "PascalCase")]
34+
Pascal,
3635
/// Rename to "camelCase" style.
37-
CamelCase,
36+
#[darling(rename = "camelCase")]
37+
Camel,
3838
/// Rename to "snake_case" style.
39-
SnakeCase,
39+
#[darling(rename = "snake_case")]
40+
Snake,
4041
/// Rename to "SCREAMING_SNAKE_CASE" style.
41-
ScreamingSnakeCase,
42+
#[darling(rename = "SCREAMING_SNAKE_CASE")]
43+
ScreamingSnake,
4244
/// Rename to "kebab-case" style.
43-
KebabCase,
45+
#[darling(rename = "kebab-case")]
46+
Kebab,
4447
/// Rename to "SCREAMING-KEBAB-CASE" style.
45-
ScreamingKebabCase,
48+
#[darling(rename = "SCREAMING-KEBAB-CASE")]
49+
ScreamingKebab,
4650
}
4751

48-
static RENAME_RULES: &[(&str, RenameRule)] = &[
49-
("lowercase", RenameRule::LowerCase),
50-
("UPPERCASE", RenameRule::UpperCase),
51-
("PascalCase", RenameRule::PascalCase),
52-
("camelCase", RenameRule::CamelCase),
53-
("snake_case", RenameRule::SnakeCase),
54-
("SCREAMING_SNAKE_CASE", RenameRule::ScreamingSnakeCase),
55-
("kebab-case", RenameRule::KebabCase),
56-
("SCREAMING-KEBAB-CASE", RenameRule::ScreamingKebabCase),
57-
];
58-
5952
impl RenameRule {
60-
/// Obrain a rename rule from a str
61-
pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError<'_>> {
62-
for (name, rule) in RENAME_RULES {
63-
if rename_all_str == *name {
64-
return Ok(*rule);
65-
}
66-
}
67-
Err(ParseError {
68-
unknown: rename_all_str,
69-
})
70-
}
71-
7253
/// Apply a renaming rule to a struct field, returning the version expected in the source.
73-
pub fn apply_to_field<'a>(&self, field: &'a str) -> Cow<'a, str> {
74-
match *self {
75-
RenameRule::None => Cow::Borrowed(field),
76-
RenameRule::LowerCase | RenameRule::SnakeCase => field.to_ascii_lowercase().into(),
77-
RenameRule::UpperCase => field.to_ascii_uppercase().into(),
78-
RenameRule::PascalCase => {
54+
pub fn apply_to_field(&self, field: &str) -> String {
55+
match self {
56+
RenameRule::Lower | RenameRule::Snake => field.to_ascii_lowercase(),
57+
RenameRule::Upper => field.to_ascii_uppercase(),
58+
RenameRule::Pascal => {
7959
let mut pascal = String::new();
8060
let mut capitalize = true;
61+
8162
for ch in field.chars() {
8263
if ch == '_' {
8364
capitalize = true;
@@ -88,39 +69,20 @@ impl RenameRule {
8869
pascal.push(ch);
8970
}
9071
}
91-
Cow::Owned(pascal)
92-
}
93-
RenameRule::CamelCase => {
94-
let pascal = RenameRule::PascalCase.apply_to_field(field);
95-
Cow::Owned(pascal[..1].to_ascii_lowercase() + &pascal[1..])
96-
}
97-
RenameRule::ScreamingSnakeCase => field.to_ascii_uppercase().into(),
98-
RenameRule::KebabCase => field.replace('_', "-").into(),
99-
RenameRule::ScreamingKebabCase => RenameRule::ScreamingSnakeCase
100-
.apply_to_field(field)
101-
.replace('_', "-")
102-
.into(),
103-
}
104-
}
105-
}
10672

107-
#[derive(Debug)]
108-
pub struct ParseError<'a> {
109-
unknown: &'a str,
110-
}
73+
pascal
74+
}
75+
RenameRule::Camel => {
76+
let pascal = RenameRule::Pascal.apply_to_field(field);
11177

112-
impl Display for ParseError<'_> {
113-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114-
f.write_str("unknown rename rule `rename_all = ")?;
115-
Debug::fmt(self.unknown, f)?;
116-
f.write_str("`, expected one of ")?;
117-
for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() {
118-
if i > 0 {
119-
f.write_str(", ")?;
78+
pascal[..1].to_ascii_lowercase() + &pascal[1..]
12079
}
121-
Debug::fmt(name, f)?;
80+
RenameRule::ScreamingSnake => field.to_ascii_uppercase(),
81+
RenameRule::Kebab => field.replace('_', "-"),
82+
RenameRule::ScreamingKebab => RenameRule::ScreamingSnake
83+
.apply_to_field(field)
84+
.replace('_', "-"),
12285
}
123-
Ok(())
12486
}
12587
}
12688

@@ -146,18 +108,17 @@ mod test {
146108
("a", "A", "A", "a", "A", "a", "A"),
147109
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
148110
] {
149-
assert_eq!(RenameRule::None.apply_to_field(original), original);
150-
assert_eq!(RenameRule::UpperCase.apply_to_field(original), upper);
151-
assert_eq!(RenameRule::PascalCase.apply_to_field(original), pascal);
152-
assert_eq!(RenameRule::CamelCase.apply_to_field(original), camel);
153-
assert_eq!(RenameRule::SnakeCase.apply_to_field(original), original);
111+
assert_eq!(RenameRule::Upper.apply_to_field(original), upper);
112+
assert_eq!(RenameRule::Pascal.apply_to_field(original), pascal);
113+
assert_eq!(RenameRule::Camel.apply_to_field(original), camel);
114+
assert_eq!(RenameRule::Snake.apply_to_field(original), original);
154115
assert_eq!(
155-
RenameRule::ScreamingSnakeCase.apply_to_field(original),
116+
RenameRule::ScreamingSnake.apply_to_field(original),
156117
screaming
157118
);
158-
assert_eq!(RenameRule::KebabCase.apply_to_field(original), kebab);
119+
assert_eq!(RenameRule::Kebab.apply_to_field(original), kebab);
159120
assert_eq!(
160-
RenameRule::ScreamingKebabCase.apply_to_field(original),
121+
RenameRule::ScreamingKebab.apply_to_field(original),
161122
screaming_kebab
162123
);
163124
}

0 commit comments

Comments
 (0)