Skip to content

Commit d2e1757

Browse files
authored
Add support specifying the map type to use (#708)
1 parent 9065106 commit d2e1757

File tree

18 files changed

+926
-40
lines changed

18 files changed

+926
-40
lines changed

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ applied. Non-required properties with types that already have a default value
5656
(such as a `Vec<T>`) simply get the `#[serde(default)]` attribute (so you won't
5757
see e.g. `Option<Vec<T>>`).
5858

59+
#### Alternate Map types
60+
61+
By default, Typify uses `std::collections::HashMap` as described above.
62+
63+
If you prefer to use `std::collections::BTreeMap` or a map type from a crate such
64+
as `indexmap::IndexMap`, you can specify this by calling `with_map_type` on the
65+
`TypeSpaceSettings` object, and providing the full path to the type you want to
66+
use. E.g. `::std::collections::BTreeMap` or `::indexmap::IndexMap`.
67+
68+
Note that for a custom map type to work you must have `T` defined to generate
69+
a struct as described in [Objects](#objects). If `T` is not defined, typify
70+
will generate code using a `serde_json::Map<String, serde_json::Value>` instead.
71+
72+
See the documentation for `TypeSpaceSettings::with_map_type` for the
73+
requirements for a map type.
74+
5975
### OneOf
6076

6177
The `oneOf` construct maps to a Rust enum. Typify maps this to the various

cargo-typify/src/lib.rs

+33
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ pub struct CliArgs {
4646
#[arg(long = "crate")]
4747
crates: Vec<CrateSpec>,
4848

49+
/// Specify the map like type to use.
50+
#[arg(long = "map-type")]
51+
map_type: Option<String>,
52+
4953
/// Specify the policy unknown crates found in schemas with the
5054
/// x-rust-type extension.
5155
#[arg(
@@ -151,6 +155,10 @@ pub fn convert(args: &CliArgs) -> Result<String> {
151155
settings.with_crate(name, version.clone(), rename.as_ref());
152156
}
153157

158+
if let Some(map_type) = &args.map_type {
159+
settings.with_map_type(map_type.clone());
160+
}
161+
154162
if let Some(unknown_crates) = &args.unknown_crates {
155163
let unknown_crates = match unknown_crates.as_str() {
156164
"generate" => UnknownPolicy::Generate,
@@ -192,6 +200,7 @@ mod tests {
192200
output: Some(PathBuf::from("-")),
193201
no_builder: false,
194202
crates: vec![],
203+
map_type: None,
195204
unknown_crates: Default::default(),
196205
};
197206

@@ -207,6 +216,7 @@ mod tests {
207216
output: Some(PathBuf::from("some_file.rs")),
208217
no_builder: false,
209218
crates: vec![],
219+
map_type: None,
210220
unknown_crates: Default::default(),
211221
};
212222

@@ -222,12 +232,32 @@ mod tests {
222232
output: None,
223233
no_builder: false,
224234
crates: vec![],
235+
map_type: None,
225236
unknown_crates: Default::default(),
226237
};
227238

228239
assert_eq!(args.output_path(), Some(PathBuf::from("input.rs")));
229240
}
230241

242+
#[test]
243+
fn test_use_btree_map() {
244+
let args = CliArgs {
245+
input: PathBuf::from("input.json"),
246+
builder: false,
247+
additional_derives: vec![],
248+
output: None,
249+
no_builder: false,
250+
crates: vec![],
251+
map_type: Some("::std::collections::BTreeMap".to_string()),
252+
unknown_crates: Default::default(),
253+
};
254+
255+
assert_eq!(
256+
args.map_type,
257+
Some("::std::collections::BTreeMap".to_string())
258+
);
259+
}
260+
231261
#[test]
232262
fn test_builder_as_default_style() {
233263
let args = CliArgs {
@@ -237,6 +267,7 @@ mod tests {
237267
output: None,
238268
no_builder: false,
239269
crates: vec![],
270+
map_type: None,
240271
unknown_crates: Default::default(),
241272
};
242273

@@ -252,6 +283,7 @@ mod tests {
252283
output: None,
253284
no_builder: true,
254285
crates: vec![],
286+
map_type: None,
255287
unknown_crates: Default::default(),
256288
};
257289

@@ -267,6 +299,7 @@ mod tests {
267299
output: None,
268300
no_builder: false,
269301
crates: vec![],
302+
map_type: None,
270303
unknown_crates: Default::default(),
271304
};
272305

cargo-typify/tests/integration.rs

+26
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,29 @@ fn test_help() {
158158
assert!(output.status.success());
159159
assert_contents("tests/outputs/help.txt", &actual);
160160
}
161+
162+
#[test]
163+
fn test_btree_map() {
164+
use assert_cmd::Command;
165+
166+
let input = concat!(env!("CARGO_MANIFEST_DIR"), "/../example.json");
167+
168+
let temp = TempDir::new("cargo-typify").unwrap();
169+
let output_file = temp.path().join("output.rs");
170+
171+
let mut cmd = Command::cargo_bin("cargo-typify").unwrap();
172+
cmd.args([
173+
"typify",
174+
input,
175+
"--map-type",
176+
"::std::collections::BTreeMap",
177+
"--output",
178+
output_file.to_str().unwrap(),
179+
])
180+
.assert()
181+
.success();
182+
183+
let actual = std::fs::read_to_string(output_file).unwrap();
184+
185+
assert_contents("tests/outputs/custom_btree_map.rs", &actual);
186+
}

cargo-typify/tests/outputs/builder.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,22 @@ pub mod error {
3535
#[doc = r""]
3636
#[doc = r" ```json"]
3737
#[doc = "{"]
38-
#[doc = " \"type\": \"object\""]
38+
#[doc = " \"type\": \"object\","]
39+
#[doc = " \"additionalProperties\": {"]
40+
#[doc = " \"type\": \"string\""]
41+
#[doc = " }"]
3942
#[doc = "}"]
4043
#[doc = r" ```"]
4144
#[doc = r" </details>"]
4245
#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)]
43-
pub struct Fruit(pub ::serde_json::Map<::std::string::String, ::serde_json::Value>);
46+
pub struct Fruit(pub ::std::collections::HashMap<::std::string::String, ::std::string::String>);
4447
impl ::std::ops::Deref for Fruit {
45-
type Target = ::serde_json::Map<::std::string::String, ::serde_json::Value>;
46-
fn deref(&self) -> &::serde_json::Map<::std::string::String, ::serde_json::Value> {
48+
type Target = ::std::collections::HashMap<::std::string::String, ::std::string::String>;
49+
fn deref(&self) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> {
4750
&self.0
4851
}
4952
}
50-
impl From<Fruit> for ::serde_json::Map<::std::string::String, ::serde_json::Value> {
53+
impl From<Fruit> for ::std::collections::HashMap<::std::string::String, ::std::string::String> {
5154
fn from(value: Fruit) -> Self {
5255
value.0
5356
}
@@ -57,8 +60,10 @@ impl From<&Fruit> for Fruit {
5760
value.clone()
5861
}
5962
}
60-
impl From<::serde_json::Map<::std::string::String, ::serde_json::Value>> for Fruit {
61-
fn from(value: ::serde_json::Map<::std::string::String, ::serde_json::Value>) -> Self {
63+
impl From<::std::collections::HashMap<::std::string::String, ::std::string::String>> for Fruit {
64+
fn from(
65+
value: ::std::collections::HashMap<::std::string::String, ::std::string::String>,
66+
) -> Self {
6267
Self(value)
6368
}
6469
}

0 commit comments

Comments
 (0)