Compare commits
No commits in common. "73c59c97d0c831664e64cece8110f08b2fdd967f" and "71e0d31d8d5688b2dfe7afb0d59bea203be4a4c3" have entirely different histories.
73c59c97d0
...
71e0d31d8d
19 changed files with 147 additions and 354 deletions
|
|
@ -38,14 +38,12 @@ repository = "https://forgejo.fireturlte.net/lazy-supplements"
|
|||
|
||||
[workspace.dependencies]
|
||||
bevy = { git = "https://github.com/bevyengine/bevy.git", rev="16ffdaea0daec11e4347d965f56c9c8e1122a488" }
|
||||
caretta-id = {path="./id", features=["rusqlite", "serde"]}
|
||||
chrono = "0.4.41"
|
||||
ciborium = "0.2.2"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
caretta-sync-core.path = "core"
|
||||
futures = { version = "0.3.31", features = ["executor"] }
|
||||
rand = "0.8.5"
|
||||
rusqlite = "0.37.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] }
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ test = ["dep:tempfile", ]
|
|||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
caretta-id.workspace = true
|
||||
chrono.workspace = true
|
||||
chrono-tz = "0.10.3"
|
||||
ciborium.workspace = true
|
||||
|
|
@ -23,7 +22,7 @@ futures.workspace = true
|
|||
iroh.workspace = true
|
||||
prost.workspace = true
|
||||
prost-types.workspace = true
|
||||
rusqlite = { workspace = true, features = ["bundled", "chrono"] }
|
||||
rusqlite = { version = "0.37.0", features = ["bundled", "chrono"] }
|
||||
serde.workspace = true
|
||||
sysinfo = "0.37.0"
|
||||
tempfile = { version = "3.20.0", optional = true }
|
||||
|
|
|
|||
91
core/src/data/local/authorization/mod.rs
Normal file
91
core/src/data/local/authorization/mod.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//! Structs about authorization.
|
||||
|
||||
mod request;
|
||||
mod response;
|
||||
|
||||
use std::os::unix::raw::time_t;
|
||||
|
||||
use chrono::{DateTime, Local, NaiveDateTime};
|
||||
use iroh::NodeId;
|
||||
pub use request::*;
|
||||
pub use response::*;
|
||||
use rusqlite::{params, types::FromSqlError, Connection};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::data::local::RusqliteRecord;
|
||||
|
||||
/// On going authorization
|
||||
pub struct Authorization {
|
||||
request_id: Uuid,
|
||||
node_id: NodeId,
|
||||
node_info: Option<String>,
|
||||
passcode: Option<String>,
|
||||
created_at: DateTime<Local>,
|
||||
updated_at: DateTime<Local>,
|
||||
}
|
||||
static TABLE_NAME: &str = "authorization";
|
||||
static DEFAULT_COLUMNS: [&str;5] = [
|
||||
"request_id",
|
||||
"node_id",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
];
|
||||
|
||||
impl Authorization {
|
||||
pub fn new_sent(node_id: NodeId, passcode: String) -> Self {
|
||||
let timestamp = Local::now();
|
||||
Self {
|
||||
node_id: node_id,
|
||||
passcode: passcode,
|
||||
created_at: timestamp.clone(),
|
||||
updated_at: timestamp
|
||||
}
|
||||
}
|
||||
pub fn new_received(node_id:)
|
||||
pub fn get_by_node_id(node_id: NodeId, connection: &Connection) -> Result<Self, rusqlite::Error> {
|
||||
connection.query_row(
|
||||
"SELECT node_id, passcode, created_at, updated_at FROM authorizaation WHRE node_id=(?1)",
|
||||
params![node_id.as_bytes()],
|
||||
Self::from_row
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
impl RusqliteRecord for Authorization {
|
||||
fn from_row(row: &rusqlite::Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
let created_at: NaiveDateTime = row.get(2)?;
|
||||
let updated_at: NaiveDateTime = row.get(3)?;
|
||||
let node_id: Vec<u8> = row.get(0)?;
|
||||
Ok(Self {
|
||||
node_id: NodeId::from_bytes(node_id[..32].try_into().or_else(|e| {
|
||||
Err(rusqlite::types::FromSqlError::InvalidBlobSize {
|
||||
expected_size: 32,
|
||||
blob_size: node_id.len()
|
||||
})
|
||||
})?).or(Err(FromSqlError::InvalidType))?,
|
||||
passcode: row.get(1)?,
|
||||
created_at: DateTime::from(created_at.and_utc()),
|
||||
updated_at: DateTime::from(updated_at.and_utc()),
|
||||
})
|
||||
}
|
||||
fn insert(&self, connection: &rusqlite::Connection) -> Result<(), rusqlite::Error> {
|
||||
connection.execute(
|
||||
"INSERT INTO authorization (node_id, passcode, created_at, updated_at) VALUES (?1, ?2, ?3, ?4)",
|
||||
(&self.node_id.as_bytes(), &self.passcode, &self.created_at.naive_utc(), &self.updated_at.naive_utc()),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn get_all(connection: &rusqlite::Connection) -> Result<Vec<Self>, rusqlite::Error> {
|
||||
let mut stmt = connection.prepare(&(String::from("SELECT ") + &DEFAULT_COLUMNS.join(", ") + " FROM " + TABLE_NAME))?;
|
||||
let rows = stmt.query_map(
|
||||
[],
|
||||
Self::from_row
|
||||
)?;
|
||||
let mut result= Vec::new();
|
||||
for row in rows {
|
||||
result.push(row?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
8
core/src/data/local/authorization/request.rs
Normal file
8
core/src/data/local/authorization/request.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
use iroh::NodeId;
|
||||
|
||||
/// Request of node authentication.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AuthorizationRequest {
|
||||
sender_id: NodeId,
|
||||
sender_info: String,
|
||||
}
|
||||
12
core/src/data/local/authorization/response.rs
Normal file
12
core/src/data/local/authorization/response.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use iroh::NodeId;
|
||||
|
||||
/// Response of node authentication.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AuthorizationResponse {
|
||||
sender_id: NodeId,
|
||||
passcode: String,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
//! Structs about authorization.
|
||||
|
||||
mod sent;
|
||||
mod received;
|
||||
|
||||
use std::os::unix::raw::time_t;
|
||||
|
||||
use chrono::{DateTime, Local, NaiveDateTime};
|
||||
use iroh::NodeId;
|
||||
pub use sent::*;
|
||||
pub use received::*;
|
||||
use rusqlite::{params, types::FromSqlError, Connection};
|
||||
use uuid::Uuid;
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
use caretta_id::{DoubleId, SingleId};
|
||||
use chrono::{DateTime, Local, NaiveDateTime};
|
||||
use iroh::{NodeId, PublicKey};
|
||||
|
||||
use crate::{data::local::LocalModel, global::LOCAL_DATABASE_CONNECTION};
|
||||
|
||||
/// Response of node authentication.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReceivedAuthorizationRequest {
|
||||
request_id: SingleId,
|
||||
public_key: PublicKey,
|
||||
node_info: String,
|
||||
created_at: DateTime<Local>,
|
||||
responded_at: Option<DateTime<Local>>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl ReceivedAuthorizationRequest {
|
||||
pub fn get_by_request_id(request_id: SingleId) -> Result<Self, rusqlite::Error> {
|
||||
todo!()
|
||||
}
|
||||
pub fn get_by_public_key(public_key: PublicKey) -> Result<Self, rusqlite::Error> {
|
||||
todo!()
|
||||
}
|
||||
pub fn get_by_local_peer_id(local_peer_id: DoubleId) -> Result<Self, rusqlite::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalModel for ReceivedAuthorizationRequest {
|
||||
const TABLE_NAME: &str = "received_authorization_request";
|
||||
const DEFAULT_COLUMNS: &[&str] = &[
|
||||
"request_id",
|
||||
"public_key",
|
||||
"node_info",
|
||||
"created_at",
|
||||
"responded_at",
|
||||
];
|
||||
fn from_default_row(row: &rusqlite::Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
let created_at: NaiveDateTime = row.get(3)?;
|
||||
let responded_at: Option<NaiveDateTime> = row.get(4)?;
|
||||
Ok(Self {
|
||||
request_id: row.get(0)?,
|
||||
public_key: PublicKey::from_bytes(&row.get(1)?).map_err(|e| rusqlite::types::FromSqlError::Other(Box::new(e)))?,
|
||||
node_info: row.get(2)?,
|
||||
created_at: DateTime::from(created_at.and_utc()),
|
||||
responded_at: responded_at.map(|x| DateTime::from(x.and_utc())),
|
||||
})
|
||||
}
|
||||
fn insert(&self) -> Result<(), rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
|
||||
connection.execute(
|
||||
&("INSERT INTO ".to_string() + Self::TABLE_NAME + " (" + &Self::DEFAULT_COLUMNS.join(", ") + ") VALUES (?1, ?2, ?3, ?4, ?5)"),
|
||||
(
|
||||
&self.request_id,
|
||||
&self.public_key.as_bytes(),
|
||||
&self.node_info,
|
||||
&self.created_at.naive_utc(),
|
||||
&self.responded_at.map(|x| x.naive_utc()),
|
||||
)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn get_all() -> Result<Vec<Self>, rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
|
||||
let mut stmt = connection.prepare(&(String::from("SELECT ") + &Self::DEFAULT_COLUMNS.join(", ") + " FROM " + Self::TABLE_NAME))?;
|
||||
let rows = stmt.query_map(
|
||||
[],
|
||||
Self::from_default_row
|
||||
)?;
|
||||
let mut result= Vec::new();
|
||||
for row in rows {
|
||||
result.push(row?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
use caretta_id::SingleId;
|
||||
use chrono::{DateTime, Local, NaiveDateTime};
|
||||
use iroh::{NodeId, PublicKey};
|
||||
use rusqlite::types::FromSqlError;
|
||||
|
||||
use crate::{data::local::LocalModel, global::LOCAL_DATABASE_CONNECTION};
|
||||
|
||||
/// Request of node authentication.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SentAuthorizationRequest {
|
||||
request_id: SingleId,
|
||||
public_key: PublicKey,
|
||||
passcode: String,
|
||||
created_at: DateTime<Local>,
|
||||
sent_at: Option<DateTime<Local>>,
|
||||
}
|
||||
|
||||
impl LocalModel for SentAuthorizationRequest {
|
||||
|
||||
const TABLE_NAME: &str = "sent_authorization";
|
||||
const DEFAULT_COLUMNS: &[&str] = &[
|
||||
"request_id",
|
||||
"public_key",
|
||||
"passcode",
|
||||
"created_at",
|
||||
"sent_at"
|
||||
];
|
||||
fn from_default_row(row: &rusqlite::Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
let created_at: NaiveDateTime = row.get(2)?;
|
||||
let sent_at: Option<NaiveDateTime> = row.get(3)?;
|
||||
Ok(Self {
|
||||
request_id: row.get(0)?,
|
||||
public_key: PublicKey::from_bytes(&row.get(1)?).map_err(|e| FromSqlError::Other(Box::new(e)))?,
|
||||
passcode: row.get(2)?,
|
||||
created_at: DateTime::from(created_at.and_utc()),
|
||||
sent_at: sent_at.map(|x| DateTime::from(x.and_utc())),
|
||||
})
|
||||
}
|
||||
fn insert(&self) -> Result<(), rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
connection.execute(
|
||||
&(String::from("INSERT INTO ") + Self::TABLE_NAME + " (" + &Self::DEFAULT_COLUMNS.join(", ") + ") VALUES (?1, ?2, ?3, ?4, ?5)"),
|
||||
(
|
||||
&self.request_id,
|
||||
&self.public_key.as_bytes(),
|
||||
&self.passcode,
|
||||
&self.created_at.naive_utc(),
|
||||
&self.sent_at.map(|x| x.naive_utc())
|
||||
),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn get_all() -> Result<Vec<Self>, rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
|
||||
let mut stmt = connection.prepare(&(String::from("SELECT ") + &Self::DEFAULT_COLUMNS.join(", ") + " FROM " + Self::TABLE_NAME))?;
|
||||
let rows = stmt.query_map(
|
||||
[],
|
||||
Self::from_default_row
|
||||
)?;
|
||||
let mut result= Vec::new();
|
||||
for row in rows {
|
||||
result.push(row?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,27 +4,6 @@ pub fn migrate(con: &mut Connection) -> Result<(), Error>{
|
|||
let tx = con.transaction()?;
|
||||
tx.execute_batch(
|
||||
"BEGIN;
|
||||
CREATE TABLE peer (
|
||||
id INTEGER PRIMARY KEY,
|
||||
local_id INTEGER NOT NULL UNIQUE,
|
||||
public_key BLOB UNIQUE NOT NULL,
|
||||
);
|
||||
CREATE TABLE received_authorization_request (
|
||||
id INTEGER PRIMARY KEY,
|
||||
request_id INTEGER NOT NULL UNIQUE,
|
||||
public_key BLOB NOT NULL UNIQUE,
|
||||
node_info TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
responded_at TEXT
|
||||
);
|
||||
CREATE TABLE sent_authorization_request (
|
||||
id INTEGER PRIMARY KEY,
|
||||
request_id INTEGER NOT NULL UNIQUE,
|
||||
public_key. BLOB NOT NULL UNIQUE,
|
||||
passcode TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
sent_at TEXT
|
||||
)
|
||||
CREATE TABLE authorized_peer (
|
||||
id INTEGER PRIMARY KEY,
|
||||
node_id BLOB NOT NULL UNIQUE,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
mod authorization_request;
|
||||
mod peer;
|
||||
mod authorization;
|
||||
pub mod migration;
|
||||
|
||||
use std::{cell::OnceCell, iter::Map, path::Path, sync::{LazyLock, OnceLock}};
|
||||
|
|
@ -9,14 +8,20 @@ use rusqlite::{ffi::Error, Connection, MappedRows, Row};
|
|||
|
||||
use crate::{config::StorageConfig, global::{CONFIG, LOCAL_DATABASE_CONNECTION}};
|
||||
|
||||
pub use authorization_request::*;
|
||||
pub use authorization::*;
|
||||
|
||||
/// Model trait for local database data.
|
||||
/// use LOCAL_DATABASE_CONNECTION for database connection.
|
||||
pub trait LocalModel: Sized {
|
||||
const TABLE_NAME: &str;
|
||||
const DEFAULT_COLUMNS: &[&str];
|
||||
fn insert(&self) -> Result<(), rusqlite::Error>;
|
||||
fn from_default_row(row: &Row<'_>) -> Result<Self, rusqlite::Error>;
|
||||
fn get_all() -> Result<Vec<Self>, rusqlite::Error>;
|
||||
pub trait RusqliteRecord: Sized {
|
||||
fn insert(&self, connection: &Connection) -> Result<(), rusqlite::Error>;
|
||||
fn from_row(row: &Row<'_>) -> Result<Self, rusqlite::Error>;
|
||||
fn get_all(connection: &Connection) -> Result<Vec<Self>, rusqlite::Error>;
|
||||
}
|
||||
|
||||
pub trait LocalRecord : RusqliteRecord{
|
||||
fn insert_global(&self) -> Result<(), rusqlite::Error> {
|
||||
self.insert(&LOCAL_DATABASE_CONNECTION.get_unchecked())
|
||||
}
|
||||
fn get_all_global() -> Result<Vec<Self>, rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
Self::get_all(&connection)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
//! Structs about cached peer.
|
||||
|
||||
use std::os::unix::raw::time_t;
|
||||
|
||||
use caretta_id::DoubleId;
|
||||
use chrono::{DateTime, Local, NaiveDateTime};
|
||||
use iroh::{NodeId, PublicKey};
|
||||
use rusqlite::{params, types::FromSqlError, Connection};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{data::local::LocalModel, global::LOCAL_DATABASE_CONNECTION};
|
||||
|
||||
/// Peer information cached in local database.
|
||||
///
|
||||
/// - Currently this only contain local id and public key (=node id) of iroh.
|
||||
/// - This is a junction table enable to use caretta-id to specify items in the UI, especially on the CLI.
|
||||
/// - Actual peer information is managed by iroh endpoint and not contained in this model.
|
||||
/// - Once a peer is authorized, it is assigned a global (=synced) ID as authorized_peer so essentially this local id targets unauthorized peers.
|
||||
///
|
||||
pub struct Peer {
|
||||
pub local_id: DoubleId,
|
||||
pub public_key: PublicKey,
|
||||
}
|
||||
|
||||
impl Peer {
|
||||
pub fn get_by_local_id(local_id: DoubleId) -> Result<Option<Self>, rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
Ok(Some(connection.query_row(
|
||||
&("SELECT ".to_string() + &Self::DEFAULT_COLUMNS.join(", ") + " FROM " + Self::TABLE_NAME + " WHERE local_id=(?1)"),
|
||||
params![local_id],
|
||||
Self::from_default_row
|
||||
)?))
|
||||
}
|
||||
pub fn get_by_public_key(public_key: PublicKey) -> Result<Option<Self>, rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
Ok(Some(connection.query_row(
|
||||
&("SELECT ".to_string() + &Self::DEFAULT_COLUMNS.join(", ") + " FROM " + Self::TABLE_NAME + " WHERE public_key=(?1)"),
|
||||
params![public_key.as_bytes()],
|
||||
Self::from_default_row
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalModel for Peer {
|
||||
const TABLE_NAME: &str = "peer";
|
||||
const DEFAULT_COLUMNS: &[&str] = &[
|
||||
"local_id",
|
||||
"public_key"
|
||||
];
|
||||
|
||||
fn from_default_row(row: &rusqlite::Row<'_>) -> Result<Self, rusqlite::Error> {
|
||||
|
||||
Ok(Self {
|
||||
local_id: row.get(0)?,
|
||||
public_key: PublicKey::from_bytes(&row.get(1)?).map_err(|e| FromSqlError::Other(Box::new(e)))?
|
||||
})
|
||||
}
|
||||
fn insert(&self) -> Result<(), rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
|
||||
connection.execute(
|
||||
&("INSERT INTO ".to_owned() + Self::TABLE_NAME + " (" + &Self::DEFAULT_COLUMNS.join(", ") + ") VALUES (?1, ?2, ?3, ?4)"),
|
||||
(&self.local_id, &self.public_key.as_bytes()),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn get_all() -> Result<Vec<Self>, rusqlite::Error> {
|
||||
let connection = LOCAL_DATABASE_CONNECTION.get_unchecked();
|
||||
let mut stmt = connection.prepare(&("SELECT ".to_string() + &Self::DEFAULT_COLUMNS.join(", ") + " FROM " + Self::TABLE_NAME))?;
|
||||
let rows = stmt.query_map(
|
||||
[],
|
||||
Self::from_default_row
|
||||
)?;
|
||||
let mut result= Vec::new();
|
||||
for row in rows {
|
||||
result.push(row?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,14 +7,7 @@ license.workspace = true
|
|||
repository.workspace = true
|
||||
|
||||
[features]
|
||||
default=[]
|
||||
rusqlite = ["dep:rusqlite"]
|
||||
serde = ["dep:serde"]
|
||||
|
||||
[dependencies]
|
||||
rand.workspace = true
|
||||
rusqlite = {workspace = true, optional = true}
|
||||
serde = {workspace = true, optional = true}
|
||||
thiserror.workspace = true
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ impl Id for DoubleId{
|
|||
|
||||
#[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.clone()) < Self::SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -105,9 +105,9 @@ impl TryFrom<u32> for DoubleId {
|
|||
}
|
||||
}
|
||||
|
||||
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))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ mod tests {
|
|||
let id: DoubleId = rand.r#gen();
|
||||
assert!(id.is_valid());
|
||||
assert_eq!(id,DoubleId::from_str(&id.to_string()).unwrap());
|
||||
assert_eq!(id, DoubleId::try_from(u32::from(&id)).unwrap())
|
||||
assert_eq!(id, DoubleId::try_from(u32::from(id.clone())).unwrap())
|
||||
}
|
||||
#[test]
|
||||
fn random_x10() {
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@ mod double;
|
|||
mod error;
|
||||
mod triple;
|
||||
mod utils;
|
||||
#[cfg(feature="rusqlite")]
|
||||
mod rusqlite;
|
||||
#[cfg(feature="serde")]
|
||||
mod serde;
|
||||
|
||||
use rand::Rng;
|
||||
pub use single::*;
|
||||
pub use double::*;
|
||||
pub use triple::*;
|
||||
pub use error::*;
|
||||
|
||||
const DOUBLE_ID_SIZE: u32 = (SingleId::SIZE as u32).pow(2);
|
||||
const TRIPLE_ID_SIZE: u64 = (SingleId::SIZE as u64).pow(3);
|
||||
|
||||
pub trait Id {
|
||||
type SizeType;
|
||||
const NIL: Self;
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
use rusqlite::{types::FromSql, Error, ToSql};
|
||||
|
||||
use crate::{DoubleId, SingleId, TripleId};
|
||||
|
||||
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| {
|
||||
Err(rusqlite::types::FromSqlError::Other(Box::new(e)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for SingleId {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||||
Ok(u16::from(self).into())
|
||||
}
|
||||
}
|
||||
|
||||
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| {
|
||||
Err(rusqlite::types::FromSqlError::Other(Box::new(e)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for DoubleId {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||||
Ok(u32::from(self).into())
|
||||
}
|
||||
}
|
||||
|
||||
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| {
|
||||
Err(rusqlite::types::FromSqlError::Other(Box::new(e)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
|err| Error::ToSqlConversionFailure(err.into())
|
||||
)?
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
|
@ -178,8 +178,8 @@ impl TryFrom<u16> for SingleId {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&SingleId> for u16 {
|
||||
fn from(value: &SingleId) -> Self {
|
||||
impl From<SingleId> for u16 {
|
||||
fn from(value: SingleId) -> Self {
|
||||
value.inner
|
||||
}
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ mod tests {
|
|||
assert!(chunk.is_valid());
|
||||
let s = chunk.to_string();
|
||||
assert_eq!(chunk,SingleId::from_str(&s).unwrap());
|
||||
let i = u16::from(&chunk);
|
||||
let i = u16::from(chunk.clone());
|
||||
assert_eq!(chunk, SingleId::try_from(i).unwrap());
|
||||
}
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl Id for TripleId{
|
|||
|
||||
#[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.clone()) < Self::SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,11 +113,11 @@ impl TryFrom<u64> for TripleId {
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ mod tests {
|
|||
let id: TripleId = rand.r#gen();
|
||||
assert!(id.is_valid());
|
||||
assert_eq!(id, TripleId::from_str(&id.to_string()).unwrap());
|
||||
assert_eq!(id, TripleId::try_from(u64::from(&id)).unwrap());
|
||||
assert_eq!(id, TripleId::try_from(u64::from(id.clone())).unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn random_x10() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue