-
-
Notifications
You must be signed in to change notification settings - Fork 250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding IndexMap
under feature flag preserve_order
#36
Conversation
The inconsistent ordering may be caused by this usage of hashmap in okapi: ...which should probably be an |
Some limited testing seems to confirm this. Also had to do expose the |
In // Old
use okapi::Map;
// New
use schemars::{Map, AltMap, AltMapEntry}; And used |
Rather than introducing AltMap, I'd rather change the usage of HashMap (which currently causes okapi to be nondeterministic) to BTreeMap/IndexMap. This would require making the key implement |
Other options for replacing
|
I removed MapAlt again because of your recent comment. Just for reference here are the other changes I made to other file/crates to implement these changes. Note: This will change everything over to use the schemars = { version = "0.7", features = ["preserve_order"] }
schemars = { version = "0.7", features = ["preserve_order"] }
# Maybe add option to okapi to use features flag?
okapi = { version = "0.4", features = ["preserve_order"] }
...
use schemars::{Map, MapEntry};
...
use std::collections::HashMap;
...
pub struct OpenApiGenerator {
settings: OpenApiSettings,
schema_generator: SchemaGenerator,
operations: Map<String, HashMap<Method, Operation>>,
}
...
pub fn add_operation(&mut self, mut op: OperationInfo) {
if let Some(op_id) = op.operation.operation_id {
// TODO do this outside add_operation
op.operation.operation_id = Some(op_id.trim_start_matches(':').replace("::", "_"));
}
match self.operations.entry(op.path) {
MapEntry::Occupied(e) => {
let path = e.key();
panic!("An OpenAPI operation has already been added for {}", path);
}
MapEntry::Vacant(e) => {
let mut map = HashMap::new();
map.insert(op.method, op.operation);
e.insert(map)
}
};
}
...
pub fn into_openapi(self) -> OpenApi {
OpenApi {
openapi: "3.0.0".to_owned(),
paths: {
let mut paths = Map::new();
for (path, map) in self.operations {
for (method, op) in map {
let path_item = paths.entry(path.clone()).or_default();
set_operation(path_item, method, op);
}
}
paths
},
....
..Default::default()
}
} I also noted that In a project I would then use it as: schemars = { version = "0.7", features = ["preserve_order"] }
# optional change (if okapi further forward this feature)
okapi = { version = "0.4", features = ["preserve_order"] } So okapi and rocket_okapi have to incorporate this change too to take effect. For the changed to this crate there is not much else to do I think. I encountered no problems while testing. I think this can be merged not and we can continue the conversation further in https://github.com/GREsau/okapi |
IndexMap
under feature flag preserve_order
IndexMap
under feature flag preserve_order
Thanks for the PR, I've merged it after a making couple of tweaks. IndexMap's Extend implementation actually doesn't require the key/value to be Copy so I could keep the simpler implementation of Merge. |
WIP: Do not merge yet
Implementation for #32
This is only a small change.
Most of the change is to make
impl<K, V> Merge for Map<K, V>
work again.Because the
Extens<(K, V)>
forIndexMap<K, V, S>
implementation relays onK: Hash + Eq + Copy, V: Copy,
As Copy is not always implemented for things like String and most structs. So I make a small implementation ofextend
in there. Withinsert
that only needs to relaysK: std::hash::Hash + Eq
. TheOrd
trait was already there. Just moved it down.Tested
I tested the code both in the okapi example and my code. Both work with and without the feature flag set.
Import in code
When testing make sure you point
okapi
,rocket-okapi
and your own code to the sameSchemars
version.Example in my code (and okapi example): (Cargo.toml)
Weird API call list order
The only odd behavior that I have noticed is that the order of the api calls is not consistent.



Order without feature flag:
Order with flag run first time:
Close and run again:
This is different every time you close and start the server again (does not even have to recompile).


I do not know how this comes. But also have not looked into this yet.
The order in the rocket output is always the same.
I have only seen this with the routes not the other parts.
Order changes in json as you can see here (both with feature flag, just closed and started server in between):
Works, proof
But here is proof that is works in other cases:


With flag:
Feedback
So what do you think? What can be changes/improved. You maybe have an idea where the order bug comes from? Maybe just timing or multi-threading?
@ThouCheese are you maybe willing to give this a try in your project to see if you spot any compatibility error?