Skip to main content

metrique_core/
namestyle.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Name styles for field inflection.
5//!
6//! # Style ordering
7//!
8//! Style-indexed arrays use the ordering defined by [`Styles`] in
9//! `metrique_writer_core::descriptor`. See [`Styles::ALL`] for the canonical order.
10
11use std::marker::PhantomData;
12
13use crate::concat::{Concatenated, EmptyConstStr, MaybeConstStr};
14
15pub(crate) mod private {
16    /// Helper trait to make `NameStyle` sealed
17    pub trait NameStyleInternal {}
18}
19
20/// This trait is used to describe name styles for [`InflectableEntry`].
21///
22/// The exact implementation of this trait is currently unstable.
23///
24/// [`InflectableEntry`]: crate::InflectableEntry
25pub trait NameStyle: private::NameStyleInternal {
26    /// Index into the per-style descriptor statics. Used by the macro to select
27    /// the correct pre-computed descriptor for this name style.
28    #[doc(hidden)]
29    const DESCRIPTOR_STYLE_INDEX: u8;
30
31    #[doc(hidden)]
32    type KebabCase: NameStyle;
33
34    #[doc(hidden)]
35    type PascalCase: NameStyle;
36
37    #[doc(hidden)]
38    type SnakeCase: NameStyle;
39
40    #[doc(hidden)]
41    type AppendPrefix<T: MaybeConstStr>: NameStyle;
42
43    /// Inflect the name, adding prefixes
44    #[doc(hidden)]
45    type Inflect<ID: MaybeConstStr, PASCAL: MaybeConstStr, SNAKE: MaybeConstStr, KEBAB: MaybeConstStr>: MaybeConstStr;
46
47    /// Inflect an affix (just inflect, without adding prefixes)
48    #[doc(hidden)]
49    type InflectAffix<ID: MaybeConstStr, PASCAL: MaybeConstStr, SNAKE: MaybeConstStr, KEBAB: MaybeConstStr>: MaybeConstStr;
50}
51
52// Style index constants: canonical definitions live in metrique-writer-core::descriptor.
53// Re-exported here for convenience (the macro imports from metrique-core).
54pub use metrique_writer_core::descriptor::{Style, Styles};
55
56/// Inflects names to the identity case
57pub struct Identity<PREFIX: MaybeConstStr = EmptyConstStr>(PhantomData<PREFIX>);
58impl<PREFIX: MaybeConstStr> private::NameStyleInternal for Identity<PREFIX> {}
59impl<PREFIX: MaybeConstStr> NameStyle for Identity<PREFIX> {
60    const DESCRIPTOR_STYLE_INDEX: u8 = Styles::PRESERVE.index;
61    type KebabCase = KebabCase<PREFIX>;
62    type PascalCase = PascalCase<PREFIX>;
63    type SnakeCase = SnakeCase<PREFIX>;
64    type AppendPrefix<P: MaybeConstStr> = Identity<Concatenated<PREFIX, P>>;
65    type Inflect<
66        ID: MaybeConstStr,
67        PASCAL: MaybeConstStr,
68        SNAKE: MaybeConstStr,
69        KEBAB: MaybeConstStr,
70    > = Concatenated<PREFIX, ID>;
71    type InflectAffix<
72        ID: MaybeConstStr,
73        PASCAL: MaybeConstStr,
74        SNAKE: MaybeConstStr,
75        KEBAB: MaybeConstStr,
76    > = ID;
77}
78
79/// inflects names to `PascalCase`
80pub struct PascalCase<PREFIX: MaybeConstStr = EmptyConstStr>(PhantomData<PREFIX>);
81impl<PREFIX: MaybeConstStr> private::NameStyleInternal for PascalCase<PREFIX> {}
82impl<PREFIX: MaybeConstStr> NameStyle for PascalCase<PREFIX> {
83    const DESCRIPTOR_STYLE_INDEX: u8 = Styles::PASCAL.index;
84    type KebabCase = KebabCase<PREFIX>;
85    type PascalCase = PascalCase<PREFIX>;
86    type SnakeCase = SnakeCase<PREFIX>;
87    type AppendPrefix<P: MaybeConstStr> = PascalCase<Concatenated<PREFIX, P>>;
88    type Inflect<
89        ID: MaybeConstStr,
90        PASCAL: MaybeConstStr,
91        SNAKE: MaybeConstStr,
92        KEBAB: MaybeConstStr,
93    > = Concatenated<PREFIX, PASCAL>;
94    type InflectAffix<
95        ID: MaybeConstStr,
96        PASCAL: MaybeConstStr,
97        SNAKE: MaybeConstStr,
98        KEBAB: MaybeConstStr,
99    > = PASCAL;
100}
101
102/// Inflects names to `snake_case`
103pub struct SnakeCase<PREFIX: MaybeConstStr = EmptyConstStr>(PhantomData<PREFIX>);
104impl<PREFIX: MaybeConstStr> private::NameStyleInternal for SnakeCase<PREFIX> {}
105impl<PREFIX: MaybeConstStr> NameStyle for SnakeCase<PREFIX> {
106    const DESCRIPTOR_STYLE_INDEX: u8 = Styles::SNAKE.index;
107    type KebabCase = KebabCase<PREFIX>;
108    type PascalCase = PascalCase<PREFIX>;
109    type SnakeCase = SnakeCase<PREFIX>;
110    type AppendPrefix<P: MaybeConstStr> = SnakeCase<Concatenated<PREFIX, P>>;
111    type Inflect<
112        ID: MaybeConstStr,
113        PASCAL: MaybeConstStr,
114        SNAKE: MaybeConstStr,
115        KEBAB: MaybeConstStr,
116    > = Concatenated<PREFIX, SNAKE>;
117    type InflectAffix<
118        ID: MaybeConstStr,
119        PASCAL: MaybeConstStr,
120        SNAKE: MaybeConstStr,
121        KEBAB: MaybeConstStr,
122    > = SNAKE;
123}
124
125/// Inflects names to `kebab-case`
126pub struct KebabCase<PREFIX: MaybeConstStr = EmptyConstStr>(PhantomData<PREFIX>);
127impl<PREFIX: MaybeConstStr> private::NameStyleInternal for KebabCase<PREFIX> {}
128impl<PREFIX: MaybeConstStr> NameStyle for KebabCase<PREFIX> {
129    const DESCRIPTOR_STYLE_INDEX: u8 = Styles::KEBAB.index;
130    type KebabCase = KebabCase<PREFIX>;
131    type PascalCase = PascalCase<PREFIX>;
132    type SnakeCase = SnakeCase<PREFIX>;
133    type AppendPrefix<P: MaybeConstStr> = KebabCase<Concatenated<PREFIX, P>>;
134    type Inflect<
135        ID: MaybeConstStr,
136        PASCAL: MaybeConstStr,
137        SNAKE: MaybeConstStr,
138        KEBAB: MaybeConstStr,
139    > = Concatenated<PREFIX, KEBAB>;
140    type InflectAffix<
141        ID: MaybeConstStr,
142        PASCAL: MaybeConstStr,
143        SNAKE: MaybeConstStr,
144        KEBAB: MaybeConstStr,
145    > = KEBAB;
146}
147
148/// Runtime-selectable name style for metric field names.
149///
150/// This mirrors the compile-time [`NameStyle`] types (`Identity`, `PascalCase`,
151/// etc.) as enum variants for use in runtime configuration.
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
153#[non_exhaustive]
154pub enum DynamicNameStyle {
155    /// Keep original field names.
156    #[default]
157    Identity,
158    /// Convert to PascalCase (e.g. `WorkersCount`).
159    PascalCase,
160    /// Convert to snake_case (e.g. `workers_count`).
161    SnakeCase,
162    /// Convert to kebab-case (e.g. `workers-count`).
163    KebabCase,
164}