Skip to content

Commit 4d6a60a

Browse files
authored
fix: use indexmap, not hashmap (#709)
Will solve stac-utils/rustac-py#85 once this propogates to **rustac-py**.
1 parent 8097725 commit 4d6a60a

File tree

9 files changed

+43
-38
lines changed

9 files changed

+43
-38
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ geo-types = "0.7.15"
4848
geoarrow = "0.4.0-beta.4"
4949
geojson = "0.24.1"
5050
http = "1.1"
51+
indexmap = { version = "2.9.0", features = ["serde"] }
5152
jsonschema = { version = "0.30.0", default-features = false }
5253
libduckdb-sys = "1.2.1"
5354
log = "0.4.25"

crates/api/Cargo.toml

+5-4
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,19 @@ async-stream = { workspace = true, optional = true }
2626
chrono.workspace = true
2727
cql2.workspace = true
2828
futures = { workspace = true, optional = true }
29-
http = { workspace = true, optional = true }
30-
reqwest = { workspace = true, features = ["json"], optional = true }
3129
geo = { workspace = true, optional = true }
3230
geojson.workspace = true
31+
http = { workspace = true, optional = true }
32+
indexmap.workspace = true
33+
reqwest = { workspace = true, features = ["json"], optional = true }
3334
serde.workspace = true
3435
serde_json.workspace = true
3536
serde_urlencoded.workspace = true
36-
stac.workspace = true
3737
stac-derive.workspace = true
38+
stac.workspace = true
3839
thiserror.workspace = true
39-
tracing.workspace = true
4040
tokio = { workspace = true, optional = true }
41+
tracing.workspace = true
4142
url.workspace = true
4243

4344
[dev-dependencies]

crates/api/src/items.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::{Error, Fields, Filter, Result, Search, Sortby};
22
use chrono::{DateTime, FixedOffset};
3+
use indexmap::IndexMap;
34
use serde::{Deserialize, Serialize};
45
use serde_json::{Map, Value};
56
use stac::{Bbox, Item};
6-
use std::collections::HashMap;
77

88
/// Parameters for the items endpoint from STAC API - Features.
99
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
@@ -97,7 +97,7 @@ pub struct GetItems {
9797

9898
/// Additional fields.
9999
#[serde(flatten)]
100-
pub additional_fields: HashMap<String, String>,
100+
pub additional_fields: IndexMap<String, String>,
101101
}
102102

103103
impl Items {
@@ -423,12 +423,12 @@ fn maybe_parse_from_rfc3339(s: &str) -> Result<Option<DateTime<FixedOffset>>> {
423423
mod tests {
424424
use super::{GetItems, Items};
425425
use crate::{Fields, Filter, Sortby, sort::Direction};
426+
use indexmap::IndexMap;
426427
use serde_json::{Map, Value, json};
427-
use std::collections::HashMap;
428428

429429
#[test]
430430
fn get_items_try_from_items() {
431-
let mut additional_fields = HashMap::new();
431+
let mut additional_fields = IndexMap::new();
432432
let _ = additional_fields.insert("token".to_string(), "foobar".to_string());
433433

434434
let get_items = GetItems {

crates/core/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ geo = { workspace = true, optional = true }
4747
geo-types = { workspace = true, optional = true }
4848
geoarrow = { workspace = true, optional = true }
4949
geojson.workspace = true
50+
indexmap.workspace = true
5051
jsonschema = { workspace = true, optional = true, features = ["resolve-http"] }
5152
log.workspace = true
5253
mime.workspace = true

crates/core/src/asset.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{Band, DataType, Statistics};
2+
use indexmap::IndexMap;
23
use serde::{Deserialize, Serialize};
34
use serde_json::{Map, Value};
45
use stac_derive::Fields;
5-
use std::collections::HashMap;
66

77
/// An Asset is an object that contains a URI to data associated with the [Item](crate::Item) that can be downloaded or streamed.
88
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Fields)]
@@ -98,7 +98,7 @@ pub trait Assets {
9898
/// let item: Item = stac::read("examples/simple-item.json").unwrap();
9999
/// assert!(!item.assets().is_empty());
100100
/// ```
101-
fn assets(&self) -> &HashMap<String, Asset>;
101+
fn assets(&self) -> &IndexMap<String, Asset>;
102102

103103
/// Returns a mut reference to this object's assets.
104104
///
@@ -111,7 +111,7 @@ pub trait Assets {
111111
/// let mut item: Item = stac::read("examples/simple-item.json").unwrap();
112112
/// item.assets_mut().insert("foo".to_string(), Asset::new("./asset.tif"));
113113
/// ```
114-
fn assets_mut(&mut self) -> &mut HashMap<String, Asset>;
114+
fn assets_mut(&mut self) -> &mut IndexMap<String, Asset>;
115115
}
116116

117117
impl Asset {

crates/core/src/collection.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use crate::{
33
SelfHref, Version,
44
};
55
use chrono::{DateTime, Utc};
6+
use indexmap::IndexMap;
67
use serde::{Deserialize, Deserializer, Serialize};
78
use serde_json::{Map, Value};
89
use stac_derive::{Fields, Links, SelfHref};
9-
use std::collections::HashMap;
1010

1111
const DEFAULT_LICENSE: &str = "other";
1212

@@ -107,12 +107,12 @@ pub struct Collection {
107107
pub links: Vec<Link>,
108108

109109
/// Dictionary of asset objects that can be downloaded, each with a unique key.
110-
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
111-
pub assets: HashMap<String, Asset>,
110+
#[serde(skip_serializing_if = "IndexMap::is_empty", default)]
111+
pub assets: IndexMap<String, Asset>,
112112

113113
/// A dictionary of assets that can be found in member Items.
114-
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
115-
pub item_assets: HashMap<String, ItemAsset>,
114+
#[serde(skip_serializing_if = "IndexMap::is_empty", default)]
115+
pub item_assets: IndexMap<String, ItemAsset>,
116116

117117
/// Additional fields not part of the `Collection` specification.
118118
#[serde(flatten)]
@@ -208,8 +208,8 @@ impl Collection {
208208
extent: Extent::default(),
209209
summaries: None,
210210
links: Vec::new(),
211-
assets: HashMap::new(),
212-
item_assets: HashMap::new(),
211+
assets: IndexMap::new(),
212+
item_assets: IndexMap::new(),
213213
additional_fields: Map::new(),
214214
self_href: None,
215215
}
@@ -380,10 +380,10 @@ impl Default for TemporalExtent {
380380
}
381381

382382
impl Assets for Collection {
383-
fn assets(&self) -> &HashMap<String, Asset> {
383+
fn assets(&self) -> &IndexMap<String, Asset> {
384384
&self.assets
385385
}
386-
fn assets_mut(&mut self) -> &mut HashMap<String, Asset> {
386+
fn assets_mut(&mut self) -> &mut IndexMap<String, Asset> {
387387
&mut self.assets
388388
}
389389
}

crates/core/src/item.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
use crate::{Asset, Assets, Bbox, Error, Fields, Href, Link, Result, STAC_VERSION, Version};
44
use chrono::{DateTime, FixedOffset, NaiveDateTime, Utc};
55
use geojson::{Feature, Geometry, feature::Id};
6+
use indexmap::IndexMap;
67
use serde::{Deserialize, Deserializer, Serialize};
78
use serde_json::{Map, Value};
89
use stac_derive::{Links, Migrate, SelfHref};
9-
use std::{collections::HashMap, path::Path};
10+
use std::path::Path;
1011
use url::Url;
1112

1213
const TOP_LEVEL_ATTRIBUTES: [&str; 8] = [
@@ -98,7 +99,7 @@ pub struct Item {
9899

99100
/// Dictionary of asset objects that can be downloaded, each with a unique key.
100101
#[serde(default)]
101-
pub assets: HashMap<String, Asset>,
102+
pub assets: IndexMap<String, Asset>,
102103

103104
/// The `id` of the STAC [Collection](crate::Collection) this `Item`
104105
/// references to.
@@ -157,7 +158,7 @@ pub struct FlatItem {
157158
pub links: Vec<Link>,
158159

159160
/// Dictionary of asset objects that can be downloaded, each with a unique key.
160-
pub assets: HashMap<String, Asset>,
161+
pub assets: IndexMap<String, Asset>,
161162

162163
/// The ID of the collection this Item is a part of.
163164
pub collection: Option<String>,
@@ -246,7 +247,7 @@ pub struct Properties {
246247
pub struct Builder {
247248
id: String,
248249
canonicalize_paths: bool,
249-
assets: HashMap<String, Asset>,
250+
assets: IndexMap<String, Asset>,
250251
}
251252

252253
impl Builder {
@@ -262,7 +263,7 @@ impl Builder {
262263
Builder {
263264
id: id.to_string(),
264265
canonicalize_paths: true,
265-
assets: HashMap::new(),
266+
assets: IndexMap::new(),
266267
}
267268
}
268269

@@ -357,7 +358,7 @@ impl Item {
357358
bbox: None,
358359
properties: Properties::default(),
359360
links: Vec::new(),
360-
assets: HashMap::new(),
361+
assets: IndexMap::new(),
361362
collection: None,
362363
additional_fields: Map::new(),
363364
self_href: None,
@@ -592,10 +593,10 @@ impl Item {
592593
}
593594

594595
impl Assets for Item {
595-
fn assets(&self) -> &HashMap<String, Asset> {
596+
fn assets(&self) -> &IndexMap<String, Asset> {
596597
&self.assets
597598
}
598-
fn assets_mut(&mut self) -> &mut HashMap<String, Asset> {
599+
fn assets_mut(&mut self) -> &mut IndexMap<String, Asset> {
599600
&mut self.assets
600601
}
601602
}

crates/extensions/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rust-version.workspace = true
1313

1414
[dependencies]
1515
geojson.workspace = true
16-
stac.workspace = true
16+
indexmap.workspace = true
1717
serde.workspace = true
1818
serde_json.workspace = true
19+
stac.workspace = true

crates/extensions/src/authentication.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
//! security spec](https://swagger.io/docs/specification/authentication/).
55
66
use crate::Extension;
7+
use indexmap::IndexMap;
78
use serde::{Deserialize, Serialize};
89
use serde_json::Value;
9-
use std::collections::HashMap;
1010

1111
/// The authentication extension fields.
1212
#[derive(Debug, Serialize, Deserialize)]
1313
pub struct Authentication {
1414
/// A property that contains all of the [scheme definitions](Scheme) used by
1515
/// [Assets](stac::Asset) and [Links](stac::Link) in the STAC [Item](crate::Item) or [Collection](crate::Collection).
16-
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
17-
pub schemes: HashMap<String, Scheme>,
16+
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
17+
pub schemes: IndexMap<String, Scheme>,
1818

1919
/// A property that specifies which schemes may be used to access an [Asset](stac::Asset)
2020
/// or [Link](stac::Link).
@@ -60,8 +60,8 @@ pub struct Scheme {
6060
/// OAuth flows: `authorizationCode` | `implicit` | `password` |
6161
/// `clientCredentials`. The OAuth2 Flow Object applies for oauth2, the
6262
/// Signed URL Object applies to signedUrl.
63-
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
64-
pub flows: HashMap<String, Flow>,
63+
#[serde(skip_serializing_if = "IndexMap::is_empty", default)]
64+
pub flows: IndexMap<String, Flow>,
6565

6666
/// OpenID Connect URL to discover OpenID configuration values.
6767
///
@@ -94,7 +94,7 @@ pub enum Flow {
9494
/// The available scopes for the authentication scheme.
9595
///
9696
/// A map between the scope name and a short description for it. The map MAY be empty.
97-
scopes: HashMap<String, String>,
97+
scopes: IndexMap<String, String>,
9898

9999
/// The URL to be used for obtaining refresh tokens.
100100
///
@@ -115,8 +115,8 @@ pub enum Flow {
115115
authorization_api: Option<String>,
116116

117117
/// Parameter definition for requests to the authorizationApi
118-
#[serde(skip_serializing_if = "HashMap::is_empty")]
119-
parameters: HashMap<String, Parameter>,
118+
#[serde(skip_serializing_if = "IndexMap::is_empty")]
119+
parameters: IndexMap<String, Parameter>,
120120

121121
/// Key name for the signed URL field in an authorizationApi response
122122
#[serde(skip_serializing_if = "Option::is_none", rename = "responseField")]
@@ -138,7 +138,7 @@ pub struct Parameter {
138138
pub description: Option<String>,
139139

140140
/// Schema object following the [JSON Schema draft-07](Schema object following the JSON Schema draft-07).
141-
pub schema: HashMap<String, Value>,
141+
pub schema: IndexMap<String, Value>,
142142
}
143143

144144
/// Query, header, or cookie.

0 commit comments

Comments
 (0)