Skip to content

Commit f0e5037

Browse files
committed
Add files and license
1 parent 04eccaf commit f0e5037

14 files changed

+642
-0
lines changed

.github/workflows/ci.yml

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
check:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- uses: actions-rs/toolchain@v1
15+
with:
16+
profile: minimal
17+
toolchain: stable
18+
override: true
19+
components: rustfmt, clippy
20+
- uses: actions/cache@v2
21+
with:
22+
path: |
23+
~/.cargo/registry
24+
~/.cargo/git
25+
target
26+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
27+
- name: cargo check
28+
uses: actions-rs/cargo@v1
29+
with:
30+
command: check
31+
- name: cargo test
32+
uses: actions-rs/cargo@v1
33+
with:
34+
command: test
35+
- name: cargo clippy
36+
uses: actions-rs/cargo@v1
37+
with:
38+
command: clippy
39+
args: -- -D warnings
40+
- name: cargo fmt
41+
uses: actions-rs/cargo@v1
42+
with:
43+
command: fmt
44+
args: --all -- --check

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
Cargo.lock

Cargo.toml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[package]
2+
name = "xid"
3+
version = "0.1.0"
4+
license = "MIT"
5+
description = "Globally unique sortable id generator. A Rust port of https://github.com/rs/xid."
6+
keywords = ["id"]
7+
homepage = "https://github.com/kazk/xid-rs"
8+
repository = "https://github.com/kazk/xid-rs"
9+
readme = "README.md"
10+
authors = ["kazk <[email protected]>"]
11+
edition = "2018"
12+
exclude = [".github/"]
13+
14+
[dependencies]
15+
crc32fast = "^1"
16+
hostname = "^0.3"
17+
md5 = "^0.7"
18+
once_cell = "^1"
19+
rand = "^0.7"
20+
thiserror = "^1"
21+
22+
[target.'cfg(target_os = "macos")'.dependencies]
23+
sysctl = "^0.4"
24+
25+
[target.'cfg(target_os = "windows")'.dependencies]
26+
winreg = "^0.8"
27+
28+
[dev-dependencies]
29+
criterion = "0.3"
30+
31+
32+
[[bench]]
33+
name = "xid_new"
34+
harness = false
35+
36+
[[bench]]
37+
name = "xid_new_to_string"
38+
harness = false
39+
40+
[[bench]]
41+
name = "xid_id_from_str"
42+
harness = false

LICENSE.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2015 Olivier Poitrey <https://github.com/rs/xid>
4+
Copyright (c) 2020 kazk
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

README.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# xid
2+
3+
Globally unique sortable id generator. A Rust port of https://github.com/rs/xid.
4+
5+
The binary representation is compatible with the Mongo DB 12-byte [ObjectId][object-id].
6+
The value consists of:
7+
8+
- a 4-byte timestamp value in seconds since the Unix epoch
9+
- a 3-byte value based on the machine identifier
10+
- a 2-byte value based on the process id
11+
- a 3-byte incrementing counter, initialized to a random value
12+
13+
The string representation is 20 bytes, using a base32 hex variant with characters `[0-9a-v]`
14+
to retain the sortable property of the id.
15+
16+
See the original [`xid`] project for more details.
17+
18+
## Usage
19+
20+
```rust
21+
use xid;
22+
23+
fn main() {
24+
println!("{}", xid::new().to_string()); //=> bva9lbqn1bt68k8mj62g
25+
}
26+
```
27+
28+
## Examples
29+
30+
- [`cargo run --example gen`](./examples/gen.rs): Generate xid
31+
32+
[`xid`]: https://github.com/rs/xid
33+
[object-id]: https://docs.mongodb.org/manual/reference/object-id/

benches/xid_id_from_str.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use std::str::FromStr;
2+
3+
use criterion::{criterion_group, criterion_main, Criterion};
4+
5+
use xid::Id;
6+
7+
fn criterion_benchmark(c: &mut Criterion) {
8+
c.bench_function("xid::Id::from_str()", |b| {
9+
b.iter(|| Id::from_str("9m4e2mr0ui3e8a215n4g"))
10+
});
11+
}
12+
13+
criterion_group!(benches, criterion_benchmark);
14+
criterion_main!(benches);

benches/xid_new.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
3+
use xid;
4+
5+
fn criterion_benchmark(c: &mut Criterion) {
6+
c.bench_function("xid::new()", |b| b.iter(|| xid::new()));
7+
}
8+
9+
criterion_group!(benches, criterion_benchmark);
10+
criterion_main!(benches);

benches/xid_new_to_string.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
3+
use xid;
4+
5+
fn criterion_benchmark(c: &mut Criterion) {
6+
c.bench_function("xid::new().to_string()", |b| {
7+
b.iter(|| xid::new().to_string())
8+
});
9+
}
10+
11+
criterion_group!(benches, criterion_benchmark);
12+
criterion_main!(benches);

examples/gen.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use xid;
2+
3+
fn main() {
4+
println!("{}", xid::new().to_string());
5+
}

src/generator.rs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use std::sync::atomic::{AtomicU32, Ordering};
2+
use std::time::{SystemTime, UNIX_EPOCH};
3+
4+
use once_cell::sync::OnceCell;
5+
use rand::RngCore;
6+
7+
use crate::id::{Id, RAW_LEN};
8+
use crate::machine_id;
9+
use crate::pid;
10+
11+
#[derive(Debug)]
12+
pub struct Generator {
13+
counter: AtomicU32,
14+
machine_id: [u8; 3],
15+
pid: [u8; 2],
16+
}
17+
18+
pub fn get() -> &'static Generator {
19+
static INSTANCE: OnceCell<Generator> = OnceCell::new();
20+
21+
INSTANCE.get_or_init(|| Generator {
22+
counter: AtomicU32::new(init_random()),
23+
machine_id: machine_id::get(),
24+
pid: pid::get().to_be_bytes(),
25+
})
26+
}
27+
28+
impl Generator {
29+
pub fn new_id(&self) -> Id {
30+
self.with_time(&SystemTime::now())
31+
}
32+
33+
fn with_time(&self, time: &SystemTime) -> Id {
34+
// Panic if the time is before the epoch.
35+
let unix_ts = time
36+
.duration_since(UNIX_EPOCH)
37+
.expect("Clock may have gone backwards");
38+
self.generate(unix_ts.as_secs() as u32)
39+
}
40+
41+
fn generate(&self, unix_ts: u32) -> Id {
42+
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
43+
44+
let mut raw = [0u8; RAW_LEN];
45+
// 4 bytes of Timestamp (big endian)
46+
raw[0..=3].copy_from_slice(&unix_ts.to_be_bytes());
47+
// 3 bytes of Machine ID
48+
raw[4..=6].copy_from_slice(&self.machine_id);
49+
// 2 bytes of PID
50+
raw[7..=8].copy_from_slice(&self.pid);
51+
// 3 bytes of increment counter (big endian)
52+
raw[9..].copy_from_slice(&counter.to_be_bytes()[1..]);
53+
54+
Id(raw)
55+
}
56+
}
57+
58+
// https://github.com/rs/xid/blob/efa678f304ab65d6d57eedcb086798381ae22206/id.go#L136
59+
fn init_random() -> u32 {
60+
let mut bs = [0u8; 3];
61+
rand::thread_rng().fill_bytes(&mut bs);
62+
u32::from_be_bytes([0, bs[0], bs[1], bs[2]])
63+
}

0 commit comments

Comments
 (0)