Skip to content
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

Implement Ord for Position, RoomName, ObjectId and RawObjectId #238

Merged
merged 2 commits into from
Aug 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Unreleased
- Fix typos in JavaScript code for `game::market::get_order` and `Nuke::launch_room_name`
- Add support for accessing intershard resource amounts, which currently only includes subscription
tokens, under `game::resources`.
- Implement `PartialOrd` and `Ord` for `Position`, `RoomName`, `RawObjectId` and `ObjectId`. See
documentation for ordering specifications.
- Remove remaining usages of internal `get_from_js!` macro, as it was minimally useful
- Improve syntax and consistency of some internal macros

Expand Down
39 changes: 36 additions & 3 deletions src/local/object_id.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
cmp::{Eq, PartialEq},
cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
Expand Down Expand Up @@ -35,11 +35,32 @@ pub use raw::*;
/// With that said, using this can provide nice type inference, and should have
/// few disadvantages to the lower-level alternative, [`RawObjectId`].
///
/// ---
/// # Conversion
///
/// Use `into` to convert between `ObjectId<T>` and [`RawObjectId`], and
/// [`ObjectId::into_type`] to change the type this `ObjectId` points to freely.
// Copy, Clone, Debug, PartialEq, Eq, Hash implemented manually below
///
/// # Ordering
///
/// To facilitate use as a key in a [`BTreeMap`] or other similar data
/// structures, `ObjectId` implements [`PartialOrd`] and [`Ord`].
///
/// `ObjectId`'s are ordered by the corresponding order of their underlying
/// byte values. This agrees with:
///
/// - lexicographical ordering of the object id strings
/// - JavaScript's ordering of object id strings
/// - ordering of [`RawObjectId`]s
///
/// **Note:** when running on the official screeps server, or on a private
/// server backed by a MongoDB database, this ordering roughly corresponds to
/// creation order. The first four bytes of a MongoDB-created `ObjectId` [are
/// seconds since the epoch when the id was created][1], so up to a second
/// accuracy, these ids will be sorted by object creation time.
///
/// [`BTreeMap`]: std::collections::BTreeMap
/// [1]: https://docs.mongodb.com/manual/reference/method/ObjectId/
// Copy, Clone, Debug, PartialEq, Eq, Hash, PartialEq, Eq implemented manually below
#[derive(Serialize, Deserialize)]
#[serde(transparent, bound = "")]
pub struct ObjectId<T> {
Expand Down Expand Up @@ -74,6 +95,18 @@ impl<T> Hash for ObjectId<T> {
self.raw.hash(state)
}
}
impl<T> PartialOrd<ObjectId<T>> for ObjectId<T> {
#[inline]
fn partial_cmp(&self, other: &ObjectId<T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T> Ord for ObjectId<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.raw.cmp(&other.raw)
}
}

impl<T> FromStr for ObjectId<T> {
type Err = RawObjectIdParseError;
Expand Down
15 changes: 14 additions & 1 deletion src/local/object_id/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@ const MAX_PACKED_VAL: u128 = (1 << (32 * 3)) - 1;
/// To convert to a String in JavaScript, either use
/// [`RawObjectId::to_array_string`], or [`RawObjectId::unsafe_as_uploaded`].
/// See method documentation for more information.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
///
/// # Ordering
///
/// To facilitate use as a key in a [`BTreeMap`] or other similar data
/// structures, `ObjectId` implements [`PartialOrd`] and [`Ord`].
///
/// `RawObjectId`'s are ordered by the corresponding order of their underlying
/// byte values. See [`ObjectId`] documentation for more information.
///
/// [`BTreeMap`]: std::collections::BTreeMap
/// [`Ord`]: std::cmp::Ord
/// [`PartialOrd`]: std::cmp::PartialOrd
/// [`ObjectId`]: super::ObjectId
#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
#[serde(transparent)]
pub struct RawObjectId {
packed: [u32; 3],
Expand Down
34 changes: 34 additions & 0 deletions src/local/room_name.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
cmp::{Ord, Ordering, PartialOrd},
error,
fmt::{self, Write},
ops,
Expand All @@ -10,6 +11,22 @@ use arrayvec::ArrayString;
use super::{HALF_WORLD_SIZE, VALID_ROOM_NAME_COORDINATES};

/// A structure representing a room name.
///
/// # Ordering
///
/// To facilitate use as a key in a [`BTreeMap`] or other similar data
/// structures, `RoomName` implements [`PartialOrd`] and [`Ord`].
///
/// `RoomName`s are ordered first by y position, then by x position. North is
/// considered less than south, and west less than east.
///
/// The total ordering is `N127W127`, `N127W126`, `N127W125`, ..., `N127W0`,
/// `N127E0`, ..., `N127E127`, `N126W127`, ..., `S127E126`, `S127E127`.
///
/// This follows left-to-right reading order when looking at the Screeps map
/// from above.
///
/// [`BTreeMap`]: std::collections::BTreeMap
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct RoomName {
/// A bit-packed integer, containing, from highest-order to lowest:
Expand All @@ -23,6 +40,8 @@ pub struct RoomName {
///
/// This is the same representation of the upper 16 bits of [`Position`]'s
/// packed representation.
///
/// [`Position`]: crate::local::Position
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, great thanks, I saw the doc compiler complaining about that earlier!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I almost made a separate PR but decided just to include it in this one

packed: u16,
}

Expand Down Expand Up @@ -361,6 +380,21 @@ impl PartialEq<RoomName> for &String {
}
}

impl PartialOrd for RoomName {
#[inline]
fn partial_cmp(&self, other: &RoomName) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for RoomName {
fn cmp(&self, other: &Self) -> Ordering {
self.y_coord()
.cmp(&other.y_coord())
.then_with(|| self.x_coord().cmp(&other.x_coord()))
}
}

mod serde {
use std::fmt;

Expand Down
39 changes: 38 additions & 1 deletion src/local/room_position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
//! This is a reimplementation/translation of the `RoomPosition` code originally
//! written in JavaScript. All RoomPosition to RoomPosition operations in this
//! file stay within Rust.
use std::fmt;
use std::{
cmp::{Ord, Ordering, PartialOrd},
fmt,
};

use super::{RoomName, HALF_WORLD_SIZE};

Expand Down Expand Up @@ -75,8 +78,27 @@ mod world_utils;
/// };
/// ```
///
/// # Ordering
///
/// To facilitate use as a key in a [`BTreeMap`] or other similar data
/// structures, `Position` implements [`PartialOrd`] and [`Ord`].
///
/// `Position`s are ordered first by ascending world `y` position, then by
/// ascending world `x` position. World `x` and `y` here simply extend the x,y
/// coords within the room `E0S0` throughout the map.
///
/// Looking at positions as tuples `(world_x, world_y)`, the sorting obeys rules
/// such as:
///
/// - `(a, 0) < (b, 1)` for any `a`, `b`
/// - `(0, c) < (1, c)` for any `c`
///
/// This follows left-to-right reading order when looking at the Screeps map
/// from above.
///
/// [`bincode`]: https://github.com/servo/bincode
/// [`HasPosition::pos`]: crate::HasPosition::pos
/// [`BTreeMap`]: std::collections::BTreeMap
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct Position {
Expand Down Expand Up @@ -236,6 +258,21 @@ impl Position {
}
}

impl PartialOrd for Position {
#[inline]
fn partial_cmp(&self, other: &Position) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for Position {
fn cmp(&self, other: &Self) -> Ordering {
self.world_y()
.cmp(&other.world_y())
.then_with(|| self.world_x().cmp(&other.world_x()))
}
}

mod stdweb {
use stdweb::{Reference, Value};

Expand Down