Skip to content

Commit 20c56f0

Browse files
tyiloabr-egnisabelatkinson
authored
RUST-2017 Add method to construct an ObjectId from its parts (#492)
--------- Co-authored-by: Abraham Egnor <[email protected]> Co-authored-by: Isabel Atkinson <[email protected]>
1 parent a72431e commit 20c56f0

File tree

2 files changed

+39
-17
lines changed

2 files changed

+39
-17
lines changed

src/oid.rs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -166,27 +166,34 @@ impl ObjectId {
166166
/// Generates a new [`ObjectId`], represented in bytes.
167167
/// See the [docs](http://www.mongodb.com/docs/manual/reference/object-id/)
168168
/// for more information.
169-
pub fn new() -> ObjectId {
170-
let timestamp = ObjectId::gen_timestamp();
171-
let process_id = ObjectId::gen_process_id();
172-
let counter = ObjectId::gen_count();
173-
174-
let mut buf: [u8; 12] = [0; 12];
175-
buf[TIMESTAMP_OFFSET..(TIMESTAMP_SIZE + TIMESTAMP_OFFSET)]
176-
.clone_from_slice(&timestamp[..TIMESTAMP_SIZE]);
177-
buf[PROCESS_ID_OFFSET..(PROCESS_ID_SIZE + PROCESS_ID_OFFSET)]
178-
.clone_from_slice(&process_id[..PROCESS_ID_SIZE]);
179-
buf[COUNTER_OFFSET..(COUNTER_SIZE + COUNTER_OFFSET)]
180-
.clone_from_slice(&counter[..COUNTER_SIZE]);
181-
182-
ObjectId::from_bytes(buf)
169+
pub fn new() -> Self {
170+
let timestamp = Self::gen_timestamp();
171+
let process_id = Self::gen_process_id();
172+
let counter = Self::gen_count();
173+
174+
Self::from_parts(timestamp, process_id, counter)
183175
}
184176

185177
/// Constructs a new ObjectId wrapper around the raw byte representation.
186178
pub const fn from_bytes(bytes: [u8; 12]) -> ObjectId {
187179
ObjectId { id: bytes }
188180
}
189181

182+
/// Construct an `ObjectId` from its parts.
183+
/// See the [docs](http://www.mongodb.com/docs/manual/reference/object-id/)
184+
/// for more information.
185+
pub fn from_parts(seconds_since_epoch: u32, process_id: [u8; 5], counter: [u8; 3]) -> Self {
186+
let mut bytes = [0; 12];
187+
188+
bytes[TIMESTAMP_OFFSET..(TIMESTAMP_OFFSET + TIMESTAMP_SIZE)]
189+
.clone_from_slice(&u32::to_be_bytes(seconds_since_epoch));
190+
bytes[PROCESS_ID_OFFSET..(PROCESS_ID_OFFSET + PROCESS_ID_SIZE)]
191+
.clone_from_slice(&process_id);
192+
bytes[COUNTER_OFFSET..(COUNTER_OFFSET + COUNTER_SIZE)].clone_from_slice(&counter);
193+
194+
Self::from_bytes(bytes)
195+
}
196+
190197
/// Creates an ObjectID using a 12-byte (24-char) hexadecimal string.
191198
pub fn parse_str(s: impl AsRef<str>) -> Result<ObjectId> {
192199
let s = s.as_ref();
@@ -237,8 +244,7 @@ impl ObjectId {
237244
}
238245

239246
/// Generates a new timestamp representing the current seconds since epoch.
240-
/// Represented in Big Endian.
241-
fn gen_timestamp() -> [u8; 4] {
247+
fn gen_timestamp() -> u32 {
242248
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
243249
let timestamp: u32 = (js_sys::Date::now() / 1000.0) as u32;
244250
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
@@ -248,7 +254,8 @@ impl ObjectId {
248254
.as_secs()
249255
.try_into()
250256
.unwrap(); // will succeed until 2106 since timestamp is unsigned
251-
timestamp.to_be_bytes()
257+
258+
timestamp
252259
}
253260

254261
/// Generate a random 5-byte array.

src/tests/modules/oid.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,18 @@ fn fromstr_oid() {
5858
let actual_s = hex::encode(oid_res.unwrap().bytes());
5959
assert_eq!(s, &actual_s, "parsed and expected oids differ");
6060
}
61+
62+
#[test]
63+
fn oid_from_parts() {
64+
let _guard = LOCK.run_concurrently();
65+
let seconds_since_epoch = 123;
66+
let process_id = [4, 5, 6, 7, 8];
67+
let counter = [9, 10, 11];
68+
let oid = ObjectId::from_parts(seconds_since_epoch, process_id, counter);
69+
assert_eq!(
70+
oid.timestamp().timestamp_millis(),
71+
i64::from(seconds_since_epoch) * 1000
72+
);
73+
assert_eq!(&oid.bytes()[4..9], &process_id);
74+
assert_eq!(&oid.bytes()[9..], &counter);
75+
}

0 commit comments

Comments
 (0)