diff --git a/Cargo.lock b/Cargo.lock index efada3e..5922a8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,10 +28,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "fastid" -version = "0.0.2" +version = "0.0.4" dependencies = [ + "hex", "once_cell", "pyo3", + "rand", "rs-snowflake", "ulid", "uuid", @@ -54,6 +56,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "indoc" version = "2.0.4" diff --git a/Cargo.toml b/Cargo.toml index 0a19911..b94c8c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fastid" -version = "0.0.3" +version = "0.0.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -15,6 +15,8 @@ ulid="1.1.0" pyo3="0.20.0" rs-snowflake = "0.6.0" once_cell = "1.19.0" +rand = "0.8.5" +hex = "0.4.3" [dependencies.uuid] version = "1.6.1" diff --git a/README.md b/README.md index 6f7b8a5..d0c9337 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ Created for the easy and fast generation of various IDs # Supported IDs - ulid - snowflake -- uuid v7 (If you intend to use uuid in your database, this can be a great choice) \ No newline at end of file +- uuid v7 (If you intend to use uuid in your database, this can be a great choice) diff --git a/fastid.pyi b/fastid.pyi index c965b67..c10feba 100644 --- a/fastid.pyi +++ b/fastid.pyi @@ -12,3 +12,7 @@ def snowflake_int(machine_id: int = 1, node_id: int = 1) -> int: def uuid_v7() -> str: ... + + +def object_id() -> str: + """test""" diff --git a/python/test/test_fastid.py b/python/test/test_fastid.py index 8734bb9..39d02ff 100644 --- a/python/test/test_fastid.py +++ b/python/test/test_fastid.py @@ -1,13 +1,14 @@ import timeit import uuid +import bson import fastid -from ulid import microsecond +import ulid def test_ulid(): print() - print("ulid-py ", timeit.timeit(lambda: microsecond.new().str, number=10000)) + print("ulid-py ", timeit.timeit(lambda: ulid.microsecond.new().str, number=10000)) print("fastid.ulid", timeit.timeit(lambda: fastid.ulid(), number=10000)) @@ -21,3 +22,9 @@ def test_uuid(): print() print("uuid.uuid4 ", timeit.timeit(lambda: uuid.uuid4(), number=10000)) print("fastid.uuid_v7", timeit.timeit(lambda: fastid.uuid_v7(), number=10000)) + + +def test_objectid(): + print() + print("bson.ObjectId", timeit.timeit(lambda: bson.ObjectId(), number=10000)) + print("fastid.object_id", timeit.timeit(lambda: fastid.object_id(), number=10000)) diff --git a/src/lib.rs b/src/lib.rs index aa1e837..488138b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,15 @@ use std::sync::Mutex; + use once_cell::sync::Lazy; use pyo3::prelude::*; use snowflake::SnowflakeIdGenerator; use ulid::Ulid; use uuid::Uuid; +use crate::objectid::ObjectId; + +mod objectid; + static SNOWFLAKE_GENERATOR: Lazy> = Lazy::new(|| { Mutex::new(SnowflakeIdGenerator::new(1, 1)) }); @@ -40,6 +45,10 @@ fn uuid_v7() -> PyResult { Ok(Uuid::now_v7().to_string()) } +#[pyfunction] +fn object_id() -> PyResult { + Ok(ObjectId::new().to_hex_string()) +} #[pymodule] fn fastid(_py: Python, m: &PyModule) -> PyResult<()> { @@ -50,5 +59,7 @@ fn fastid(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(uuid_v7, m)?)?; + m.add_function(wrap_pyfunction!(object_id, m)?)?; + Ok(()) } diff --git a/src/objectid.rs b/src/objectid.rs new file mode 100644 index 0000000..5f81550 --- /dev/null +++ b/src/objectid.rs @@ -0,0 +1,29 @@ +use std::time::{SystemTime, UNIX_EPOCH}; +use rand::Rng; + +#[derive(Debug)] +pub struct ObjectId([u8; 12]); + +impl ObjectId { + pub fn new() -> Self { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("SystemTime before UNIX EPOCH!") + .as_secs() as u32; + + let mut rng = rand::thread_rng(); + let random_bytes = rng.gen::<[u8; 5]>(); + let counter = rng.gen::<[u8; 3]>(); + + let mut bytes = [0; 12]; + bytes[0..4].copy_from_slice(×tamp.to_be_bytes()); + bytes[4..9].copy_from_slice(&random_bytes); + bytes[9..12].copy_from_slice(&counter); + + ObjectId(bytes) + } + + pub fn to_hex_string(&self) -> String { + hex::encode(self.0) + } +} \ No newline at end of file