Compare commits
No commits in common. "26dda29c8d9b702942bbd6951e5d1dd0c00e125c" and "9ee5156dfc042a25c3d3405972592a8ad520d026" have entirely different histories.
26dda29c8d
...
9ee5156dfc
20 changed files with 146 additions and 346 deletions
|
|
@ -26,7 +26,7 @@ caretta-sync-macros = { path="macros", optional = true}
|
|||
caretta-sync-core = {workspace = true, features = ["test"]}
|
||||
|
||||
[workspace]
|
||||
members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy", "tripod-id"]
|
||||
members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy", "id"]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
|
|
@ -38,7 +38,7 @@ repository = "https://forgejo.fireturlte.net/lazy-supplements"
|
|||
|
||||
[workspace.dependencies]
|
||||
bevy = { git = "https://github.com/bevyengine/bevy.git", rev="16ffdaea0daec11e4347d965f56c9c8e1122a488" }
|
||||
tripod-id = {path="./tripod-id", features=["prost", "rusqlite", "serde"]}
|
||||
caretta-id = {path="./id", features=["rusqlite", "serde"]}
|
||||
chrono = "0.4.41"
|
||||
ciborium = "0.2.2"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ test = ["dep:tempfile", ]
|
|||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
tripod-id.workspace = true
|
||||
caretta-id.workspace = true
|
||||
chrono.workspace = true
|
||||
chrono-tz = "0.10.3"
|
||||
ciborium.workspace = true
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use caretta_sync::{
|
|||
config::P2pConfig,
|
||||
proto::cached_peer_service_server::CachedPeerServiceServer,
|
||||
server::ServerTrait,
|
||||
rpc::service::iroh::CachedPeerService
|
||||
rpc::service::cached_peer::CachedPeerService
|
||||
};
|
||||
use libp2p::{futures::StreamExt, noise, swarm::SwarmEvent, tcp, yamux};
|
||||
use tokio::net::UnixListener;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "tripod-id"
|
||||
name = "caretta-id"
|
||||
edition.workspace = true
|
||||
version = "0.1.0-alpha"
|
||||
description.workspace = true
|
||||
|
|
@ -8,17 +8,13 @@ repository.workspace = true
|
|||
|
||||
[features]
|
||||
default=[]
|
||||
prost = ["dep:prost", "dep:prost-build"]
|
||||
rusqlite = ["dep:rusqlite"]
|
||||
serde = ["dep:serde"]
|
||||
|
||||
[dependencies]
|
||||
prost = { workspace = true, optional = true }
|
||||
rand.workspace = true
|
||||
rusqlite = {workspace = true, optional = true}
|
||||
serde = {workspace = true, optional = true}
|
||||
thiserror.workspace = true
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = {version = "0.14.1", optional = true}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
# Tripod ID
|
||||
Distributable user-friendly id.
|
||||
|
||||
# Carreta ID
|
||||
Random user-friendly id for distubuted system for personal data.
|
||||
## Examples
|
||||
|
||||
- `123` : shortest version
|
||||
|
|
@ -2,51 +2,51 @@ use std::{fmt::Display, str::FromStr};
|
|||
|
||||
use rand::{distributions::Standard, prelude::Distribution, Rng};
|
||||
|
||||
use crate::{utils::is_delimiter, Error, TripodId, Single};
|
||||
use crate::{utils::is_delimiter, Error, Id, SingleId};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Double{
|
||||
inner: (Single, Single)
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct DoubleId{
|
||||
inner: (SingleId, SingleId)
|
||||
}
|
||||
|
||||
impl TripodId for Double{
|
||||
impl Id for DoubleId{
|
||||
type SizeType = u32;
|
||||
const SIZE: Self::SizeType = (Single::SIZE as u32).pow(2);
|
||||
const SIZE: Self::SizeType = (SingleId::SIZE as u32).pow(2);
|
||||
/// ```
|
||||
/// use tripod_id::{TripodId, Double};
|
||||
/// use caretta_id::{Id, DoubleId};
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(Double::NIL, Double::from_str("000-000").unwrap());
|
||||
/// assert_eq!(Double::NIL, Double::try_from(0).unwrap());
|
||||
/// assert_eq!(DoubleId::NIL, DoubleId::from_str("000-000").unwrap());
|
||||
/// assert_eq!(DoubleId::NIL, DoubleId::try_from(0).unwrap());
|
||||
/// ```
|
||||
const NIL: Self = Self{
|
||||
inner: (Single::NIL, Single::NIL)
|
||||
inner: (SingleId::NIL, SingleId::NIL)
|
||||
};
|
||||
|
||||
/// ```
|
||||
/// use tripod_id::{TripodId, Double};
|
||||
/// use caretta_id::{Id, DoubleId};
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(Double::MAX, Double::from_str("zzz-zzz").unwrap());
|
||||
/// assert_eq!(Double::MAX, Double::try_from(1291467968).unwrap());
|
||||
/// assert_eq!(DoubleId::MAX, DoubleId::from_str("zzz-zzz").unwrap());
|
||||
/// assert_eq!(DoubleId::MAX, DoubleId::try_from(1291467968).unwrap());
|
||||
/// ```
|
||||
const MAX: Self = Self{
|
||||
inner: (Single::MAX, Single::MAX)
|
||||
inner: (SingleId::MAX, SingleId::MAX)
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
fn is_valid(&self) -> bool {
|
||||
self.inner.0.is_valid() && self.inner.1.is_valid() && (u32::from(*self) < Self::SIZE)
|
||||
self.inner.0.is_valid() && self.inner.1.is_valid() && (u32::from(self) < Self::SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Double {
|
||||
impl Display for DoubleId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}-{}", self.inner.0, self.inner.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Double {
|
||||
impl FromStr for DoubleId {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
|
|
@ -55,7 +55,7 @@ impl FromStr for Double {
|
|||
7 => {
|
||||
let delimiter = s[3..4].chars().next().unwrap();
|
||||
if is_delimiter(delimiter) {
|
||||
Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[4..7])?))
|
||||
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[4..7])?))
|
||||
} else {
|
||||
Err(Error::InvalidDelimiter{
|
||||
found: vec![delimiter],
|
||||
|
|
@ -65,7 +65,7 @@ impl FromStr for Double {
|
|||
|
||||
}
|
||||
6 => {
|
||||
Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[3..6])?))
|
||||
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[3..6])?))
|
||||
}
|
||||
x => Err(Error::InvalidLength{
|
||||
expected: (6, 7),
|
||||
|
|
@ -78,36 +78,36 @@ impl FromStr for Double {
|
|||
}
|
||||
|
||||
|
||||
impl Distribution<Double> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Double {
|
||||
Double {
|
||||
impl Distribution<DoubleId> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> DoubleId {
|
||||
DoubleId {
|
||||
inner: (rng.r#gen(), rng.r#gen())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for Double {
|
||||
impl TryFrom<u32> for DoubleId {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
if value < Self::SIZE {
|
||||
Ok(Self{
|
||||
inner: (
|
||||
Single::try_from(u16::try_from(value/(Single::SIZE as u32)).unwrap())?,
|
||||
Single::try_from(u16::try_from(value % (Single::SIZE as u32)).unwrap())?
|
||||
SingleId::try_from(u16::try_from(value/(SingleId::SIZE as u32)).unwrap())?,
|
||||
SingleId::try_from(u16::try_from(value % (SingleId::SIZE as u32)).unwrap())?
|
||||
)})
|
||||
} else {
|
||||
Err(Error::OutsideOfRange{
|
||||
expected: Self::SIZE as u64,
|
||||
found: value as u64
|
||||
expected: Self::SIZE as usize,
|
||||
found: value as usize
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Double> for u32 {
|
||||
fn from(value: Double) -> Self {
|
||||
u32::from(u16::from(value.inner.0)) * u32::from(Single::SIZE) + u32::from(u16::from(value.inner.1))
|
||||
impl From<&DoubleId> for u32 {
|
||||
fn from(value: &DoubleId) -> Self {
|
||||
u32::from(u16::from(&value.inner.0)) * u32::from(SingleId::SIZE) + u32::from(u16::from(&value.inner.1))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,10 +119,10 @@ mod tests {
|
|||
where
|
||||
R: Rng
|
||||
{
|
||||
let id: Double = rand.r#gen();
|
||||
let id: DoubleId = rand.r#gen();
|
||||
assert!(id.is_valid());
|
||||
assert_eq!(id,Double::from_str(&id.to_string()).unwrap());
|
||||
assert_eq!(id, Double::try_from(u32::from(id)).unwrap())
|
||||
assert_eq!(id,DoubleId::from_str(&id.to_string()).unwrap());
|
||||
assert_eq!(id, DoubleId::try_from(u32::from(&id)).unwrap())
|
||||
}
|
||||
#[test]
|
||||
fn random_x10() {
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
pub enum Error {
|
||||
#[error("expected under {expected}, found {found}")]
|
||||
OutsideOfRange{
|
||||
expected: u64,
|
||||
found: u64,
|
||||
expected: usize,
|
||||
found: usize,
|
||||
},
|
||||
#[error("Invalid chunk: {0}")]
|
||||
InvalidChunk(String),
|
||||
24
id/src/lib.rs
Normal file
24
id/src/lib.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
mod single;
|
||||
mod double;
|
||||
mod error;
|
||||
mod triple;
|
||||
mod utils;
|
||||
#[cfg(feature="rusqlite")]
|
||||
mod rusqlite;
|
||||
#[cfg(feature="serde")]
|
||||
mod serde;
|
||||
|
||||
pub use single::*;
|
||||
pub use double::*;
|
||||
pub use triple::*;
|
||||
pub use error::*;
|
||||
|
||||
pub trait Id {
|
||||
type SizeType;
|
||||
const NIL: Self;
|
||||
const MAX: Self;
|
||||
const SIZE: Self::SizeType;
|
||||
#[cfg(test)]
|
||||
fn is_valid(&self) -> bool;
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use rusqlite::{types::FromSql, Error, ToSql};
|
||||
|
||||
use crate::{Double, Single, Triple};
|
||||
use crate::{DoubleId, SingleId, TripleId};
|
||||
|
||||
impl FromSql for Single {
|
||||
impl FromSql for SingleId {
|
||||
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
|
||||
let int = u16::column_result(value)?;
|
||||
Self::try_from(int).or_else(|e| {
|
||||
|
|
@ -11,13 +11,13 @@ impl FromSql for Single {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToSql for Single {
|
||||
impl ToSql for SingleId {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||||
Ok(u16::from(*self).into())
|
||||
Ok(u16::from(self).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for Double {
|
||||
impl FromSql for DoubleId {
|
||||
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
|
||||
let int = u32::column_result(value)?;
|
||||
Self::try_from(int).or_else(|e| {
|
||||
|
|
@ -26,13 +26,13 @@ impl FromSql for Double {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToSql for Double {
|
||||
impl ToSql for DoubleId {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||||
Ok(u32::from(*self).into())
|
||||
Ok(u32::from(self).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for Triple {
|
||||
impl FromSql for TripleId {
|
||||
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
|
||||
let int = u64::column_result(value)?;
|
||||
Self::try_from(int).or_else(|e| {
|
||||
|
|
@ -41,10 +41,10 @@ impl FromSql for Triple {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToSql for Triple {
|
||||
impl ToSql for TripleId {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||||
Ok(rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Integer(
|
||||
i64::try_from(u64::from(*self)).map_err(
|
||||
i64::try_from(u64::from(self)).map_err(
|
||||
|err| Error::ToSqlConversionFailure(err.into())
|
||||
)?
|
||||
)))
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use rand::{distributions::Standard, prelude::Distribution, Rng};
|
||||
use rand::{distributions::{uniform::UniformInt, Standard}, prelude::Distribution, Rng};
|
||||
|
||||
use crate::{error::Error, TripodId};
|
||||
use crate::{error::Error, Id};
|
||||
|
||||
const CHARACTERS: &[u8;33] = b"0123456789abcdefghjkmnpqrstuvwxyz";
|
||||
const BASE: u16 = 33;
|
||||
|
|
@ -91,8 +91,8 @@ fn str_to_u16(s: &str) -> Result<u16, Error> {
|
|||
fn u16_to_string(int: u16) -> Result<String, Error> {
|
||||
if int >= CUBED_BASE {
|
||||
return Err(Error::OutsideOfRange{
|
||||
expected: CUBED_BASE as u64,
|
||||
found: int as u64
|
||||
expected: CUBED_BASE as usize,
|
||||
found: int as usize
|
||||
})
|
||||
}
|
||||
let first_char = char::from(CHARACTERS[usize::try_from(int / SQUARED_BASE).unwrap()]);
|
||||
|
|
@ -101,35 +101,35 @@ fn u16_to_string(int: u16) -> Result<String, Error> {
|
|||
Ok(format!("{}{}{}", first_char, second_char, third_char))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Single{
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SingleId{
|
||||
inner: u16
|
||||
}
|
||||
|
||||
|
||||
impl TripodId for Single {
|
||||
impl Id for SingleId {
|
||||
type SizeType = u16;
|
||||
const SIZE: Self::SizeType = CUBED_BASE;
|
||||
|
||||
/// ```
|
||||
/// use tripod_id::{Single, TripodId};
|
||||
/// use caretta_id::{SingleId, Id};
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(Single::NIL, Single::from_str("000").unwrap());
|
||||
/// assert_eq!(Single::NIL, Single::try_from(0).unwrap());
|
||||
/// assert_eq!(SingleId::NIL, SingleId::from_str("000").unwrap());
|
||||
/// assert_eq!(SingleId::NIL, SingleId::try_from(0).unwrap());
|
||||
/// ```
|
||||
const NIL: Single = Single{
|
||||
const NIL: SingleId = SingleId{
|
||||
inner: 0
|
||||
};
|
||||
|
||||
/// ```
|
||||
/// use tripod_id::{TripodId, Single};
|
||||
/// use caretta_id::{Id, SingleId};
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(Single::MAX, Single::from_str("zzz").unwrap());
|
||||
/// assert_eq!(Single::MAX, Single::try_from(35936).unwrap());
|
||||
/// assert_eq!(SingleId::MAX, SingleId::from_str("zzz").unwrap());
|
||||
/// assert_eq!(SingleId::MAX, SingleId::try_from(35936).unwrap());
|
||||
/// ```
|
||||
const MAX: Single = Single{
|
||||
const MAX: SingleId = SingleId{
|
||||
inner: Self::SIZE-1
|
||||
};
|
||||
|
||||
|
|
@ -139,13 +139,13 @@ impl TripodId for Single {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for Single {
|
||||
impl Display for SingleId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", u16_to_string(self.inner).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Single {
|
||||
impl FromStr for SingleId {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
|
|
@ -155,15 +155,15 @@ impl FromStr for Single {
|
|||
}
|
||||
}
|
||||
|
||||
impl Distribution<Single> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Single {
|
||||
Single {
|
||||
inner: rng.gen_range(0..Single::SIZE)
|
||||
impl Distribution<SingleId> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> SingleId {
|
||||
SingleId {
|
||||
inner: rng.gen_range(0..SingleId::SIZE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for Single {
|
||||
impl TryFrom<u16> for SingleId {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||
|
|
@ -171,15 +171,15 @@ impl TryFrom<u16> for Single {
|
|||
Ok(Self{inner: value})
|
||||
} else {
|
||||
Err(Error::OutsideOfRange{
|
||||
expected: Self::SIZE as u64,
|
||||
found: value as u64
|
||||
expected: Self::SIZE as usize,
|
||||
found: value as usize
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Single> for u16 {
|
||||
fn from(value: Single) -> Self {
|
||||
impl From<&SingleId> for u16 {
|
||||
fn from(value: &SingleId) -> Self {
|
||||
value.inner
|
||||
}
|
||||
}
|
||||
|
|
@ -190,29 +190,16 @@ impl From<Single> for u16 {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature="prost")]
|
||||
fn assert_prost(id: Single) {
|
||||
use crate::SingleMessage;
|
||||
let message = SingleMessage::from(*id);
|
||||
assert_eq!(message.is_valid());
|
||||
let result = Single::try_from(message).unwrap();
|
||||
assert_eq!(id, result);
|
||||
}
|
||||
|
||||
fn assert_id(id: Single) {
|
||||
assert!(id.is_valid());
|
||||
let s = id.to_string();
|
||||
assert_eq!(id,Single::from_str(&s).unwrap());
|
||||
let i = u16::from(id);
|
||||
assert_eq!(id, Single::try_from(i).unwrap());
|
||||
}
|
||||
|
||||
fn assert_random<R>(rand: &mut R)
|
||||
where
|
||||
R: Rng
|
||||
{
|
||||
let chunk: Single = rand.r#gen();
|
||||
|
||||
let chunk: SingleId = rand.r#gen();
|
||||
assert!(chunk.is_valid());
|
||||
let s = chunk.to_string();
|
||||
assert_eq!(chunk,SingleId::from_str(&s).unwrap());
|
||||
let i = u16::from(&chunk);
|
||||
assert_eq!(chunk, SingleId::try_from(i).unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn random_x10() {
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
use crate::{utils::is_delimiter, Double, Error, Single};
|
||||
use crate::{utils::is_delimiter, DoubleId, Error, SingleId};
|
||||
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use rand::{distributions::Standard, prelude::Distribution, Rng};
|
||||
|
||||
use crate::TripodId;
|
||||
use crate::Id;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Triple {
|
||||
inner: (Single, Single, Single)
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct TripleId {
|
||||
inner: (SingleId, SingleId, SingleId)
|
||||
}
|
||||
|
||||
impl TripodId for Triple{
|
||||
impl Id for TripleId{
|
||||
type SizeType = u64;
|
||||
const SIZE: Self::SizeType = (Single::SIZE as u64).pow(3);
|
||||
const SIZE: Self::SizeType = (SingleId::SIZE as u64).pow(3);
|
||||
/// ```
|
||||
/// use tripod_id::{TripodId, Triple};
|
||||
/// use caretta_id::{Id, TripleId};
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(Triple::NIL, Triple::from_str("000-000-000").unwrap());
|
||||
/// assert_eq!(Triple::NIL, Triple::try_from(0).unwrap());
|
||||
/// assert_eq!(TripleId::NIL, TripleId::from_str("000-000-000").unwrap());
|
||||
/// assert_eq!(TripleId::NIL, TripleId::try_from(0).unwrap());
|
||||
/// ```
|
||||
const NIL: Self = Self{
|
||||
inner: (Single::NIL, Single::NIL, Single::NIL)
|
||||
inner: (SingleId::NIL, SingleId::NIL, SingleId::NIL)
|
||||
};
|
||||
|
||||
/// ```
|
||||
/// use tripod_id::{TripodId, Triple};
|
||||
/// use caretta_id::{Id, TripleId};
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(Triple::MAX, Triple::from_str("zzz-zzz-zzz").unwrap());
|
||||
/// assert_eq!(Triple::MAX, Triple::try_from(46411484401952).unwrap());
|
||||
/// assert_eq!(TripleId::MAX, TripleId::from_str("zzz-zzz-zzz").unwrap());
|
||||
/// assert_eq!(TripleId::MAX, TripleId::try_from(46411484401952).unwrap());
|
||||
/// ```
|
||||
const MAX: Self = Self{
|
||||
inner: (Single::MAX, Single::MAX, Single::MAX)
|
||||
inner: (SingleId::MAX, SingleId::MAX, SingleId::MAX)
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
fn is_valid(&self) -> bool {
|
||||
self.inner.0.is_valid() && self.inner.1.is_valid() && self.inner.2.is_valid() && (u64::from(*self) < Self::SIZE)
|
||||
self.inner.0.is_valid() && self.inner.1.is_valid() && self.inner.2.is_valid() && (u64::from(self) < Self::SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Triple {
|
||||
impl Display for TripleId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}-{}-{}", self.inner.0, self.inner.1, self.inner.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Triple {
|
||||
impl FromStr for TripleId {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
|
|
@ -60,7 +60,7 @@ impl FromStr for Triple {
|
|||
s[7..8].chars().next().unwrap(),
|
||||
];
|
||||
if is_delimiter(delimiter[0]) && is_delimiter(delimiter[1]) {
|
||||
Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[4..7])?,Single::from_str(&s[8..11])?))
|
||||
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[4..7])?,SingleId::from_str(&s[8..11])?))
|
||||
} else {
|
||||
Err(Error::InvalidDelimiter{
|
||||
found: Vec::from(delimiter),
|
||||
|
|
@ -70,7 +70,7 @@ impl FromStr for Triple {
|
|||
|
||||
}
|
||||
9 => {
|
||||
Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[3..6])?,Single::from_str(&s[6..9])?))
|
||||
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[3..6])?,SingleId::from_str(&s[6..9])?))
|
||||
}
|
||||
x => {
|
||||
Err(Self::Err::InvalidLength{
|
||||
|
|
@ -85,39 +85,39 @@ impl FromStr for Triple {
|
|||
}
|
||||
|
||||
|
||||
impl Distribution<Triple> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Triple {
|
||||
Triple {
|
||||
impl Distribution<TripleId> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> TripleId {
|
||||
TripleId {
|
||||
inner: (rng.r#gen(), rng.r#gen(), rng.r#gen())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for Triple {
|
||||
impl TryFrom<u64> for TripleId {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
if value < Self::SIZE {
|
||||
Ok(Self{
|
||||
inner: (
|
||||
Single::try_from(u16::try_from(value / (Double::SIZE as u64)).unwrap())?,
|
||||
Single::try_from(u16::try_from((value % (Double::SIZE as u64)) /(Single::SIZE as u64)).unwrap())?,
|
||||
Single::try_from(u16::try_from(value % (Single::SIZE as u64)).unwrap())?
|
||||
SingleId::try_from(u16::try_from(value / (DoubleId::SIZE as u64)).unwrap())?,
|
||||
SingleId::try_from(u16::try_from((value % (DoubleId::SIZE as u64)) /(SingleId::SIZE as u64)).unwrap())?,
|
||||
SingleId::try_from(u16::try_from(value % (SingleId::SIZE as u64)).unwrap())?
|
||||
)})
|
||||
} else {
|
||||
Err(Error::OutsideOfRange{
|
||||
expected: Self::SIZE as u64,
|
||||
found: value as u64
|
||||
expected: Self::SIZE as usize,
|
||||
found: value as usize
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Triple> for u64 {
|
||||
fn from(value: Triple) -> Self {
|
||||
(u16::from(value.inner.0) as u64) * (Double::SIZE as u64)
|
||||
+ (u16::from(value.inner.1) as u64) * (Single::SIZE as u64)
|
||||
+ (u16::from(value.inner.2) as u64)
|
||||
impl From<&TripleId> for u64 {
|
||||
fn from(value: &TripleId) -> Self {
|
||||
(u16::from(&value.inner.0) as u64) * (DoubleId::SIZE as u64)
|
||||
+ (u16::from(&value.inner.1) as u64) * (SingleId::SIZE as u64)
|
||||
+ (u16::from(&value.inner.2) as u64)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,10 +129,10 @@ mod tests {
|
|||
where
|
||||
R: Rng
|
||||
{
|
||||
let id: Triple = rand.r#gen();
|
||||
let id: TripleId = rand.r#gen();
|
||||
assert!(id.is_valid());
|
||||
assert_eq!(id, Triple::from_str(&id.to_string()).unwrap());
|
||||
assert_eq!(id, Triple::try_from(u64::from(id)).unwrap());
|
||||
assert_eq!(id, TripleId::from_str(&id.to_string()).unwrap());
|
||||
assert_eq!(id, TripleId::try_from(u64::from(&id)).unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn random_x10() {
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use crate::Single;
|
||||
use crate::SingleId;
|
||||
|
||||
|
||||
pub fn is_delimiter(c: char) -> bool {
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[cfg(feature="prost")]
|
||||
prost_build::compile_protos(
|
||||
&["proto/tripod_id.proto"],
|
||||
&["proto/"]
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
syntax = "proto3";
|
||||
package fireturtle.tripod_id;
|
||||
|
||||
// Single size tripod id message
|
||||
message Single {
|
||||
uint32 id = 1;
|
||||
}
|
||||
|
||||
// Double size tripod id message
|
||||
message Double {
|
||||
uint32 id = 1;
|
||||
}
|
||||
|
||||
// Triple size tripod id message
|
||||
message Triple {
|
||||
uint64 id = 1;
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
mod single;
|
||||
mod double;
|
||||
mod error;
|
||||
mod triple;
|
||||
mod utils;
|
||||
#[cfg(feature="rusqlite")]
|
||||
mod rusqlite;
|
||||
#[cfg(feature="serde")]
|
||||
mod serde;
|
||||
|
||||
pub use single::*;
|
||||
pub use double::*;
|
||||
pub use triple::*;
|
||||
pub use error::*;
|
||||
|
||||
#[cfg(feature="prost")]
|
||||
pub mod prost;
|
||||
#[cfg(feature="prost")]
|
||||
pub use prost::{ SingleMessage, DoubleMessage, TripleMessage };
|
||||
|
||||
pub trait TripodId {
|
||||
type SizeType;
|
||||
const NIL: Self;
|
||||
const MAX: Self;
|
||||
const SIZE: Self::SizeType;
|
||||
#[cfg(test)]
|
||||
fn is_valid(&self) -> bool;
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fmt::Display, fmt::Debug, str::FromStr};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature="prost")]
|
||||
fn assert_prost(id: T) where
|
||||
T: TripodId<SizeType = I> + Debug + Display + FromStr<Err=Error> + PartialEq + TryFrom<I, Error = Error> + Copy,
|
||||
I: From<T> {
|
||||
use crate::SingleMessage;
|
||||
let message = SingleMessage::from(*id);
|
||||
assert_eq!(message.is_valid());
|
||||
let result = Single::try_from(message).unwrap();
|
||||
assert_eq!(id, result);
|
||||
}
|
||||
|
||||
fn assert_id<T, I> (id: T) where
|
||||
T: TripodId<SizeType = I> + Debug + Display + FromStr<Err=Error> + PartialEq + TryFrom<I, Error = Error> + Copy,
|
||||
I: From<T>
|
||||
{
|
||||
assert!(id.is_valid());
|
||||
let s = id.to_string();
|
||||
assert_eq!(id,T::from_str(&s).unwrap());
|
||||
let i = T::SizeType::from(id);
|
||||
assert_eq!(id, T::try_from(i).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
use prost::Name;
|
||||
|
||||
use crate::{prost::Double, Error, TripodId};
|
||||
|
||||
impl Name for Double {
|
||||
const NAME: &'static str = "Double";
|
||||
const PACKAGE: &'static str = super::PACKAGE_NAME;
|
||||
}
|
||||
|
||||
impl Double {
|
||||
#[cfg(test)]
|
||||
pub fn is_valid(&self) -> bool {
|
||||
use crate::TripodId;
|
||||
|
||||
self.id < u32::from(crate::Double::SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Double> for Double {
|
||||
fn from(value: crate::Double) -> Self {
|
||||
Self {
|
||||
id: u32::from(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<Double> for crate::Double {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Double) -> Result<Self, Self::Error> {
|
||||
Self::try_from(
|
||||
value.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
mod generated {
|
||||
include!(concat!(env!("OUT_DIR"), "/fireturtle.tripod_id.rs"));
|
||||
}
|
||||
|
||||
mod single;
|
||||
mod double;
|
||||
mod triple;
|
||||
|
||||
pub use generated::*;
|
||||
const PACKAGE_NAME: &'static str = "fireturtle.tripod_id";
|
||||
pub type SingleMessage = Single;
|
||||
pub type DoubleMessage = Double;
|
||||
pub type TripleMessage = Triple;
|
||||
|
||||
pub trait TrypodIdMessage: From<Self::TrypodId> {
|
||||
type TrypodId: crate::TripodId + TryFrom<Self>;
|
||||
|
||||
#[cfg(test)]
|
||||
fn is_valid(&self) -> bool;
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
use prost::Name;
|
||||
|
||||
use crate::{prost::Single, Error, TripodId};
|
||||
|
||||
impl Name for Single {
|
||||
const NAME: &'static str = "Single";
|
||||
const PACKAGE: &'static str = super::PACKAGE_NAME;
|
||||
}
|
||||
|
||||
impl Single {
|
||||
#[cfg(test)]
|
||||
pub fn is_valid(&self) -> bool {
|
||||
use crate::TripodId;
|
||||
|
||||
self.id < u32::from(crate::Single::SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Single> for Single {
|
||||
fn from(value: crate::Single) -> Self {
|
||||
Self {
|
||||
id: u32::from(u16::from(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<Single> for crate::Single {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Single) -> Result<Self, Self::Error> {
|
||||
Self::try_from(
|
||||
u16::try_from(value.id).or(Err(Error::OutsideOfRange {
|
||||
expected: u64::from(crate::Single::SIZE),
|
||||
found: u64::from(value.id)
|
||||
}))?
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
use prost::Name;
|
||||
|
||||
use crate::{prost::Triple, Error, TripodId};
|
||||
|
||||
impl Name for Triple {
|
||||
const NAME: &'static str = "Triple";
|
||||
const PACKAGE: &'static str = super::PACKAGE_NAME;
|
||||
}
|
||||
|
||||
impl Triple {
|
||||
#[cfg(test)]
|
||||
pub fn is_valid(&self) -> bool {
|
||||
use crate::TripodId;
|
||||
|
||||
self.id < crate::Triple::SIZE
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Triple> for Triple {
|
||||
fn from(value: crate::Triple) -> Self {
|
||||
Self {
|
||||
id: u64::from(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<Triple> for crate::Triple {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Triple) -> Result<Self, Self::Error> {
|
||||
Self::try_from(
|
||||
value.id
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue