Rename caretta-id to tripod-id

This commit is contained in:
fluo10 2025-09-23 22:20:18 +09:00
parent 9ee5156dfc
commit 4793a96587
16 changed files with 141 additions and 101 deletions

View file

@ -26,7 +26,7 @@ caretta-sync-macros = { path="macros", optional = true}
caretta-sync-core = {workspace = true, features = ["test"]} caretta-sync-core = {workspace = true, features = ["test"]}
[workspace] [workspace]
members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy", "id"] members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy", "tripod-id"]
resolver = "3" resolver = "3"
[workspace.package] [workspace.package]
@ -38,7 +38,7 @@ repository = "https://forgejo.fireturlte.net/lazy-supplements"
[workspace.dependencies] [workspace.dependencies]
bevy = { git = "https://github.com/bevyengine/bevy.git", rev="16ffdaea0daec11e4347d965f56c9c8e1122a488" } bevy = { git = "https://github.com/bevyengine/bevy.git", rev="16ffdaea0daec11e4347d965f56c9c8e1122a488" }
caretta-id = {path="./id", features=["rusqlite", "serde"]} tripod-id = {path="./tripod-id", features=["prost", "rusqlite", "serde"]}
chrono = "0.4.41" chrono = "0.4.41"
ciborium = "0.2.2" ciborium = "0.2.2"
clap = { version = "4.5.38", features = ["derive"] } clap = { version = "4.5.38", features = ["derive"] }

View file

@ -13,7 +13,7 @@ test = ["dep:tempfile", ]
[dependencies] [dependencies]
base64 = "0.22.1" base64 = "0.22.1"
caretta-id.workspace = true tripod-id.workspace = true
chrono.workspace = true chrono.workspace = true
chrono-tz = "0.10.3" chrono-tz = "0.10.3"
ciborium.workspace = true ciborium.workspace = true

View file

@ -4,7 +4,7 @@ use caretta_sync::{
config::P2pConfig, config::P2pConfig,
proto::cached_peer_service_server::CachedPeerServiceServer, proto::cached_peer_service_server::CachedPeerServiceServer,
server::ServerTrait, server::ServerTrait,
rpc::service::cached_peer::CachedPeerService rpc::service::iroh::CachedPeerService
}; };
use libp2p::{futures::StreamExt, noise, swarm::SwarmEvent, tcp, yamux}; use libp2p::{futures::StreamExt, noise, swarm::SwarmEvent, tcp, yamux};
use tokio::net::UnixListener; use tokio::net::UnixListener;

View file

@ -1,5 +1,5 @@
[package] [package]
name = "caretta-id" name = "tripod-id"
edition.workspace = true edition.workspace = true
version = "0.1.0-alpha" version = "0.1.0-alpha"
description.workspace = true description.workspace = true
@ -8,13 +8,17 @@ repository.workspace = true
[features] [features]
default=[] default=[]
prost = ["dep:prost", "dep:prost-build"]
rusqlite = ["dep:rusqlite"] rusqlite = ["dep:rusqlite"]
serde = ["dep:serde"] serde = ["dep:serde"]
[dependencies] [dependencies]
prost = { workspace = true, optional = true }
rand.workspace = true rand.workspace = true
rusqlite = {workspace = true, optional = true} rusqlite = {workspace = true, optional = true}
serde = {workspace = true, optional = true} serde = {workspace = true, optional = true}
thiserror.workspace = true thiserror.workspace = true
[build-dependencies]
prost-build = {version = "0.14.1", optional = true}

View file

@ -1,5 +1,6 @@
# Carreta ID # Tripod ID
Random user-friendly id for distubuted system for personal data. Distributable user-friendly id.
## Examples ## Examples
- `123` : shortest version - `123` : shortest version

8
tripod-id/build.rs Normal file
View file

@ -0,0 +1,8 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature="prost")]
prost_build::compile_protos(
&["proto/tripod_id.proto"],
&["proto/"]
)?;
Ok(())
}

View file

@ -0,0 +1,17 @@
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;
}

View file

@ -2,36 +2,36 @@ use std::{fmt::Display, str::FromStr};
use rand::{distributions::Standard, prelude::Distribution, Rng}; use rand::{distributions::Standard, prelude::Distribution, Rng};
use crate::{utils::is_delimiter, Error, Id, SingleId}; use crate::{utils::is_delimiter, Error, TripodId, Single};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct DoubleId{ pub struct Double{
inner: (SingleId, SingleId) inner: (Single, Single)
} }
impl Id for DoubleId{ impl TripodId for Double{
type SizeType = u32; type SizeType = u32;
const SIZE: Self::SizeType = (SingleId::SIZE as u32).pow(2); const SIZE: Self::SizeType = (Single::SIZE as u32).pow(2);
/// ``` /// ```
/// use caretta_id::{Id, DoubleId}; /// use tripod_id::{TripodId, Double};
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// assert_eq!(DoubleId::NIL, DoubleId::from_str("000-000").unwrap()); /// assert_eq!(Double::NIL, Double::from_str("000-000").unwrap());
/// assert_eq!(DoubleId::NIL, DoubleId::try_from(0).unwrap()); /// assert_eq!(Double::NIL, Double::try_from(0).unwrap());
/// ``` /// ```
const NIL: Self = Self{ const NIL: Self = Self{
inner: (SingleId::NIL, SingleId::NIL) inner: (Single::NIL, Single::NIL)
}; };
/// ``` /// ```
/// use caretta_id::{Id, DoubleId}; /// use tripod_id::{TripodId, Double};
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// assert_eq!(DoubleId::MAX, DoubleId::from_str("zzz-zzz").unwrap()); /// assert_eq!(Double::MAX, Double::from_str("zzz-zzz").unwrap());
/// assert_eq!(DoubleId::MAX, DoubleId::try_from(1291467968).unwrap()); /// assert_eq!(Double::MAX, Double::try_from(1291467968).unwrap());
/// ``` /// ```
const MAX: Self = Self{ const MAX: Self = Self{
inner: (SingleId::MAX, SingleId::MAX) inner: (Single::MAX, Single::MAX)
}; };
#[cfg(test)] #[cfg(test)]
@ -40,13 +40,13 @@ impl Id for DoubleId{
} }
} }
impl Display for DoubleId { impl Display for Double {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}-{}", self.inner.0, self.inner.1) write!(f, "{}-{}", self.inner.0, self.inner.1)
} }
} }
impl FromStr for DoubleId { impl FromStr for Double {
type Err = Error; type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -55,7 +55,7 @@ impl FromStr for DoubleId {
7 => { 7 => {
let delimiter = s[3..4].chars().next().unwrap(); let delimiter = s[3..4].chars().next().unwrap();
if is_delimiter(delimiter) { if is_delimiter(delimiter) {
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[4..7])?)) Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[4..7])?))
} else { } else {
Err(Error::InvalidDelimiter{ Err(Error::InvalidDelimiter{
found: vec![delimiter], found: vec![delimiter],
@ -65,7 +65,7 @@ impl FromStr for DoubleId {
} }
6 => { 6 => {
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[3..6])?)) Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[3..6])?))
} }
x => Err(Error::InvalidLength{ x => Err(Error::InvalidLength{
expected: (6, 7), expected: (6, 7),
@ -78,23 +78,23 @@ impl FromStr for DoubleId {
} }
impl Distribution<DoubleId> for Standard { impl Distribution<Double> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> DoubleId { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Double {
DoubleId { Double {
inner: (rng.r#gen(), rng.r#gen()) inner: (rng.r#gen(), rng.r#gen())
} }
} }
} }
impl TryFrom<u32> for DoubleId { impl TryFrom<u32> for Double {
type Error = Error; type Error = Error;
fn try_from(value: u32) -> Result<Self, Self::Error> { fn try_from(value: u32) -> Result<Self, Self::Error> {
if value < Self::SIZE { if value < Self::SIZE {
Ok(Self{ Ok(Self{
inner: ( inner: (
SingleId::try_from(u16::try_from(value/(SingleId::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())? Single::try_from(u16::try_from(value % (Single::SIZE as u32)).unwrap())?
)}) )})
} else { } else {
Err(Error::OutsideOfRange{ Err(Error::OutsideOfRange{
@ -105,9 +105,9 @@ impl TryFrom<u32> for DoubleId {
} }
} }
impl From<&DoubleId> for u32 { impl From<&Double> for u32 {
fn from(value: &DoubleId) -> Self { fn from(value: &Double) -> Self {
u32::from(u16::from(&value.inner.0)) * u32::from(SingleId::SIZE) + u32::from(u16::from(&value.inner.1)) u32::from(u16::from(&value.inner.0)) * u32::from(Single::SIZE) + u32::from(u16::from(&value.inner.1))
} }
} }
@ -119,10 +119,10 @@ mod tests {
where where
R: Rng R: Rng
{ {
let id: DoubleId = rand.r#gen(); let id: Double = rand.r#gen();
assert!(id.is_valid()); assert!(id.is_valid());
assert_eq!(id,DoubleId::from_str(&id.to_string()).unwrap()); assert_eq!(id,Double::from_str(&id.to_string()).unwrap());
assert_eq!(id, DoubleId::try_from(u32::from(&id)).unwrap()) assert_eq!(id, Double::try_from(u32::from(&id)).unwrap())
} }
#[test] #[test]
fn random_x10() { fn random_x10() {

View file

@ -13,7 +13,10 @@ pub use double::*;
pub use triple::*; pub use triple::*;
pub use error::*; pub use error::*;
pub trait Id { #[cfg(feature="prost")]
pub mod prost;
pub trait TripodId {
type SizeType; type SizeType;
const NIL: Self; const NIL: Self;
const MAX: Self; const MAX: Self;

7
tripod-id/src/prost.rs Normal file
View file

@ -0,0 +1,7 @@
{
include!(concat!(env!("OUT_DIR"), "/fireturtle.tripod_id.rs"));
}
pub use crate::fireturtle::tripod_id::*;
type SingleMessage = Single;
type DoubleMessage = Double;
type TripleMessage = Triple;

View file

@ -1,8 +1,8 @@
use rusqlite::{types::FromSql, Error, ToSql}; use rusqlite::{types::FromSql, Error, ToSql};
use crate::{DoubleId, SingleId, TripleId}; use crate::{Double, Single, Triple};
impl FromSql for SingleId { impl FromSql for Single {
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> { fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
let int = u16::column_result(value)?; let int = u16::column_result(value)?;
Self::try_from(int).or_else(|e| { Self::try_from(int).or_else(|e| {
@ -11,13 +11,13 @@ impl FromSql for SingleId {
} }
} }
impl ToSql for SingleId { impl ToSql for Single {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> { fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
Ok(u16::from(self).into()) Ok(u16::from(self).into())
} }
} }
impl FromSql for DoubleId { impl FromSql for Double {
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> { fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
let int = u32::column_result(value)?; let int = u32::column_result(value)?;
Self::try_from(int).or_else(|e| { Self::try_from(int).or_else(|e| {
@ -26,13 +26,13 @@ impl FromSql for DoubleId {
} }
} }
impl ToSql for DoubleId { impl ToSql for Double {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> { fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
Ok(u32::from(self).into()) Ok(u32::from(self).into())
} }
} }
impl FromSql for TripleId { impl FromSql for Triple {
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> { fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
let int = u64::column_result(value)?; let int = u64::column_result(value)?;
Self::try_from(int).or_else(|e| { Self::try_from(int).or_else(|e| {
@ -41,7 +41,7 @@ impl FromSql for TripleId {
} }
} }
impl ToSql for TripleId { impl ToSql for Triple {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> { fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
Ok(rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Integer( 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(

View file

@ -1,8 +1,8 @@
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, str::FromStr};
use rand::{distributions::{uniform::UniformInt, Standard}, prelude::Distribution, Rng}; use rand::{distributions::Standard, prelude::Distribution, Rng};
use crate::{error::Error, Id}; use crate::{error::Error, TripodId};
const CHARACTERS: &[u8;33] = b"0123456789abcdefghjkmnpqrstuvwxyz"; const CHARACTERS: &[u8;33] = b"0123456789abcdefghjkmnpqrstuvwxyz";
const BASE: u16 = 33; const BASE: u16 = 33;
@ -102,34 +102,34 @@ fn u16_to_string(int: u16) -> Result<String, Error> {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SingleId{ pub struct Single{
inner: u16 inner: u16
} }
impl Id for SingleId { impl TripodId for Single {
type SizeType = u16; type SizeType = u16;
const SIZE: Self::SizeType = CUBED_BASE; const SIZE: Self::SizeType = CUBED_BASE;
/// ``` /// ```
/// use caretta_id::{SingleId, Id}; /// use tripod_id::{Single, TripodId};
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// assert_eq!(SingleId::NIL, SingleId::from_str("000").unwrap()); /// assert_eq!(Single::NIL, Single::from_str("000").unwrap());
/// assert_eq!(SingleId::NIL, SingleId::try_from(0).unwrap()); /// assert_eq!(Single::NIL, Single::try_from(0).unwrap());
/// ``` /// ```
const NIL: SingleId = SingleId{ const NIL: Single = Single{
inner: 0 inner: 0
}; };
/// ``` /// ```
/// use caretta_id::{Id, SingleId}; /// use tripod_id::{TripodId, Single};
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// assert_eq!(SingleId::MAX, SingleId::from_str("zzz").unwrap()); /// assert_eq!(Single::MAX, Single::from_str("zzz").unwrap());
/// assert_eq!(SingleId::MAX, SingleId::try_from(35936).unwrap()); /// assert_eq!(Single::MAX, Single::try_from(35936).unwrap());
/// ``` /// ```
const MAX: SingleId = SingleId{ const MAX: Single = Single{
inner: Self::SIZE-1 inner: Self::SIZE-1
}; };
@ -139,13 +139,13 @@ impl Id for SingleId {
} }
} }
impl Display for SingleId { impl Display for Single {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", u16_to_string(self.inner).unwrap()) write!(f, "{}", u16_to_string(self.inner).unwrap())
} }
} }
impl FromStr for SingleId { impl FromStr for Single {
type Err = Error; type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -155,15 +155,15 @@ impl FromStr for SingleId {
} }
} }
impl Distribution<SingleId> for Standard { impl Distribution<Single> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> SingleId { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Single {
SingleId { Single {
inner: rng.gen_range(0..SingleId::SIZE) inner: rng.gen_range(0..Single::SIZE)
} }
} }
} }
impl TryFrom<u16> for SingleId { impl TryFrom<u16> for Single {
type Error = Error; type Error = Error;
fn try_from(value: u16) -> Result<Self, Self::Error> { fn try_from(value: u16) -> Result<Self, Self::Error> {
@ -178,8 +178,8 @@ impl TryFrom<u16> for SingleId {
} }
} }
impl From<&SingleId> for u16 { impl From<&Single> for u16 {
fn from(value: &SingleId) -> Self { fn from(value: &Single) -> Self {
value.inner value.inner
} }
} }
@ -194,12 +194,12 @@ mod tests {
where where
R: Rng R: Rng
{ {
let chunk: SingleId = rand.r#gen(); let chunk: Single = rand.r#gen();
assert!(chunk.is_valid()); assert!(chunk.is_valid());
let s = chunk.to_string(); let s = chunk.to_string();
assert_eq!(chunk,SingleId::from_str(&s).unwrap()); assert_eq!(chunk,Single::from_str(&s).unwrap());
let i = u16::from(&chunk); let i = u16::from(&chunk);
assert_eq!(chunk, SingleId::try_from(i).unwrap()); assert_eq!(chunk, Single::try_from(i).unwrap());
} }
#[test] #[test]
fn random_x10() { fn random_x10() {

View file

@ -1,39 +1,39 @@
use crate::{utils::is_delimiter, DoubleId, Error, SingleId}; use crate::{utils::is_delimiter, Double, Error, Single};
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, str::FromStr};
use rand::{distributions::Standard, prelude::Distribution, Rng}; use rand::{distributions::Standard, prelude::Distribution, Rng};
use crate::Id; use crate::TripodId;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct TripleId { pub struct Triple {
inner: (SingleId, SingleId, SingleId) inner: (Single, Single, Single)
} }
impl Id for TripleId{ impl TripodId for Triple{
type SizeType = u64; type SizeType = u64;
const SIZE: Self::SizeType = (SingleId::SIZE as u64).pow(3); const SIZE: Self::SizeType = (Single::SIZE as u64).pow(3);
/// ``` /// ```
/// use caretta_id::{Id, TripleId}; /// use tripod_id::{TripodId, Triple};
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// assert_eq!(TripleId::NIL, TripleId::from_str("000-000-000").unwrap()); /// assert_eq!(Triple::NIL, Triple::from_str("000-000-000").unwrap());
/// assert_eq!(TripleId::NIL, TripleId::try_from(0).unwrap()); /// assert_eq!(Triple::NIL, Triple::try_from(0).unwrap());
/// ``` /// ```
const NIL: Self = Self{ const NIL: Self = Self{
inner: (SingleId::NIL, SingleId::NIL, SingleId::NIL) inner: (Single::NIL, Single::NIL, Single::NIL)
}; };
/// ``` /// ```
/// use caretta_id::{Id, TripleId}; /// use tripod_id::{TripodId, Triple};
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
/// assert_eq!(TripleId::MAX, TripleId::from_str("zzz-zzz-zzz").unwrap()); /// assert_eq!(Triple::MAX, Triple::from_str("zzz-zzz-zzz").unwrap());
/// assert_eq!(TripleId::MAX, TripleId::try_from(46411484401952).unwrap()); /// assert_eq!(Triple::MAX, Triple::try_from(46411484401952).unwrap());
/// ``` /// ```
const MAX: Self = Self{ const MAX: Self = Self{
inner: (SingleId::MAX, SingleId::MAX, SingleId::MAX) inner: (Single::MAX, Single::MAX, Single::MAX)
}; };
#[cfg(test)] #[cfg(test)]
@ -42,13 +42,13 @@ impl Id for TripleId{
} }
} }
impl Display for TripleId { impl Display for Triple {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}-{}-{}", self.inner.0, self.inner.1, self.inner.2) write!(f, "{}-{}-{}", self.inner.0, self.inner.1, self.inner.2)
} }
} }
impl FromStr for TripleId { impl FromStr for Triple {
type Err = Error; type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -60,7 +60,7 @@ impl FromStr for TripleId {
s[7..8].chars().next().unwrap(), s[7..8].chars().next().unwrap(),
]; ];
if is_delimiter(delimiter[0]) && is_delimiter(delimiter[1]) { if is_delimiter(delimiter[0]) && is_delimiter(delimiter[1]) {
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[4..7])?,SingleId::from_str(&s[8..11])?)) Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[4..7])?,Single::from_str(&s[8..11])?))
} else { } else {
Err(Error::InvalidDelimiter{ Err(Error::InvalidDelimiter{
found: Vec::from(delimiter), found: Vec::from(delimiter),
@ -70,7 +70,7 @@ impl FromStr for TripleId {
} }
9 => { 9 => {
Ok((SingleId::from_str(&s[0..3])?,SingleId::from_str(&s[3..6])?,SingleId::from_str(&s[6..9])?)) Ok((Single::from_str(&s[0..3])?,Single::from_str(&s[3..6])?,Single::from_str(&s[6..9])?))
} }
x => { x => {
Err(Self::Err::InvalidLength{ Err(Self::Err::InvalidLength{
@ -85,24 +85,24 @@ impl FromStr for TripleId {
} }
impl Distribution<TripleId> for Standard { impl Distribution<Triple> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> TripleId { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Triple {
TripleId { Triple {
inner: (rng.r#gen(), rng.r#gen(), rng.r#gen()) inner: (rng.r#gen(), rng.r#gen(), rng.r#gen())
} }
} }
} }
impl TryFrom<u64> for TripleId { impl TryFrom<u64> for Triple {
type Error = Error; type Error = Error;
fn try_from(value: u64) -> Result<Self, Self::Error> { fn try_from(value: u64) -> Result<Self, Self::Error> {
if value < Self::SIZE { if value < Self::SIZE {
Ok(Self{ Ok(Self{
inner: ( inner: (
SingleId::try_from(u16::try_from(value / (DoubleId::SIZE as u64)).unwrap())?, Single::try_from(u16::try_from(value / (Double::SIZE as u64)).unwrap())?,
SingleId::try_from(u16::try_from((value % (DoubleId::SIZE as u64)) /(SingleId::SIZE as u64)).unwrap())?, Single::try_from(u16::try_from((value % (Double::SIZE as u64)) /(Single::SIZE as u64)).unwrap())?,
SingleId::try_from(u16::try_from(value % (SingleId::SIZE as u64)).unwrap())? Single::try_from(u16::try_from(value % (Single::SIZE as u64)).unwrap())?
)}) )})
} else { } else {
Err(Error::OutsideOfRange{ Err(Error::OutsideOfRange{
@ -113,10 +113,10 @@ impl TryFrom<u64> for TripleId {
} }
} }
impl From<&TripleId> for u64 { impl From<&Triple> for u64 {
fn from(value: &TripleId) -> Self { fn from(value: &Triple) -> Self {
(u16::from(&value.inner.0) as u64) * (DoubleId::SIZE as u64) (u16::from(&value.inner.0) as u64) * (Double::SIZE as u64)
+ (u16::from(&value.inner.1) as u64) * (SingleId::SIZE as u64) + (u16::from(&value.inner.1) as u64) * (Single::SIZE as u64)
+ (u16::from(&value.inner.2) as u64) + (u16::from(&value.inner.2) as u64)
} }
} }
@ -129,10 +129,10 @@ mod tests {
where where
R: Rng R: Rng
{ {
let id: TripleId = rand.r#gen(); let id: Triple = rand.r#gen();
assert!(id.is_valid()); assert!(id.is_valid());
assert_eq!(id, TripleId::from_str(&id.to_string()).unwrap()); assert_eq!(id, Triple::from_str(&id.to_string()).unwrap());
assert_eq!(id, TripleId::try_from(u64::from(&id)).unwrap()); assert_eq!(id, Triple::try_from(u64::from(&id)).unwrap());
} }
#[test] #[test]
fn random_x10() { fn random_x10() {

View file

@ -1,6 +1,6 @@
use std::str::FromStr; use std::str::FromStr;
use crate::SingleId; use crate::Single;
pub fn is_delimiter(c: char) -> bool { pub fn is_delimiter(c: char) -> bool {