cbindgen/bindgen/
rename.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::borrow::Cow;
6use std::str::FromStr;
7
8/// The type of identifier to be renamed.
9#[derive(Debug, Clone, Copy)]
10pub enum IdentifierType<'a> {
11    StructMember,
12    EnumVariant { prefix: &'a str },
13    FunctionArg,
14    Type,
15    Enum,
16}
17
18impl IdentifierType<'_> {
19    fn to_str(self) -> &'static str {
20        match self {
21            IdentifierType::StructMember => "m",
22            IdentifierType::EnumVariant { .. } => "",
23            IdentifierType::FunctionArg => "a",
24            IdentifierType::Type => "",
25            IdentifierType::Enum => "",
26        }
27    }
28}
29
30/// A rule to apply to an identifier when generating bindings.
31#[derive(Debug, Clone, Default)]
32pub enum RenameRule {
33    /// Do not apply any renaming. The default.
34    #[default]
35    None,
36    /// Converts the identifier to PascalCase and adds a context dependent prefix
37    GeckoCase,
38    /// Converts the identifier to lower case.
39    LowerCase,
40    /// Converts the identifier to upper case.
41    UpperCase,
42    /// Converts the identifier to PascalCase.
43    PascalCase,
44    /// Converts the identifier to camelCase.
45    CamelCase,
46    /// Converts the identifier to snake_case.
47    SnakeCase,
48    /// Converts the identifier to SCREAMING_SNAKE_CASE.
49    ScreamingSnakeCase,
50    /// Converts the identifier to SCREAMING_SNAKE_CASE and prefixes enum variants
51    /// with the enum name.
52    QualifiedScreamingSnakeCase,
53    /// Adds a given prefix
54    Prefix(String),
55}
56
57impl RenameRule {
58    pub(crate) fn not_none(&self) -> Option<&Self> {
59        match self {
60            RenameRule::None => None,
61            other => Some(other),
62        }
63    }
64
65    /// Applies the rename rule to a string
66    pub fn apply<'a>(&self, text: &'a str, context: IdentifierType) -> Cow<'a, str> {
67        use heck::*;
68
69        if text.is_empty() {
70            return Cow::Borrowed(text);
71        }
72
73        Cow::Owned(match self {
74            RenameRule::None => return Cow::Borrowed(text),
75            RenameRule::GeckoCase => context.to_str().to_owned() + &text.to_upper_camel_case(),
76            RenameRule::LowerCase => text.to_lowercase(),
77            RenameRule::UpperCase => text.to_uppercase(),
78            RenameRule::PascalCase => text.to_pascal_case(),
79            RenameRule::CamelCase => text.to_lower_camel_case(),
80            RenameRule::SnakeCase => text.to_snake_case(),
81            RenameRule::ScreamingSnakeCase => text.to_shouty_snake_case(),
82            RenameRule::QualifiedScreamingSnakeCase => {
83                let mut result = String::new();
84
85                if let IdentifierType::EnumVariant { prefix } = context {
86                    result.push_str(
87                        &RenameRule::ScreamingSnakeCase.apply(prefix, IdentifierType::Enum),
88                    );
89                    result.push('_');
90                }
91
92                result.push_str(&RenameRule::ScreamingSnakeCase.apply(text, context));
93                result
94            }
95            RenameRule::Prefix(prefix) => prefix.to_owned() + text,
96        })
97    }
98}
99
100impl FromStr for RenameRule {
101    type Err = String;
102
103    fn from_str(s: &str) -> Result<RenameRule, Self::Err> {
104        const PREFIX: &str = "prefix:";
105        const PREFIX_LEN: usize = PREFIX.len();
106
107        match s {
108            "none" => Ok(RenameRule::None),
109            "None" => Ok(RenameRule::None),
110
111            "mGeckoCase" => Ok(RenameRule::GeckoCase),
112            "GeckoCase" => Ok(RenameRule::GeckoCase),
113            "gecko_case" => Ok(RenameRule::GeckoCase),
114
115            "lowercase" => Ok(RenameRule::LowerCase),
116            "LowerCase" => Ok(RenameRule::LowerCase),
117            "lower_case" => Ok(RenameRule::LowerCase),
118
119            "UPPERCASE" => Ok(RenameRule::UpperCase),
120            "UpperCase" => Ok(RenameRule::UpperCase),
121            "upper_case" => Ok(RenameRule::UpperCase),
122
123            "PascalCase" => Ok(RenameRule::PascalCase),
124            "pascal_case" => Ok(RenameRule::PascalCase),
125
126            "camelCase" => Ok(RenameRule::CamelCase),
127            "CamelCase" => Ok(RenameRule::CamelCase),
128            "camel_case" => Ok(RenameRule::CamelCase),
129
130            "snake_case" => Ok(RenameRule::SnakeCase),
131            "SnakeCase" => Ok(RenameRule::SnakeCase),
132
133            "SCREAMING_SNAKE_CASE" => Ok(RenameRule::ScreamingSnakeCase),
134            "ScreamingSnakeCase" => Ok(RenameRule::ScreamingSnakeCase),
135            "screaming_snake_case" => Ok(RenameRule::ScreamingSnakeCase),
136
137            "QUALIFIED_SCREAMING_SNAKE_CASE" => Ok(RenameRule::QualifiedScreamingSnakeCase),
138            "QualifiedScreamingSnakeCase" => Ok(RenameRule::QualifiedScreamingSnakeCase),
139            "qualified_screaming_snake_case" => Ok(RenameRule::QualifiedScreamingSnakeCase),
140
141            s if s.starts_with(PREFIX) => Ok(RenameRule::Prefix(s[PREFIX_LEN..].to_string())),
142
143            _ => Err(format!("Unrecognized RenameRule: '{}'.", s)),
144        }
145    }
146}
147
148deserialize_enum_str!(RenameRule);