use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::{fmt::Display, str::FromStr};
use serde::{Deserialize, Serialize};
use xxhash_rust::xxh64::Xxh64;
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct ConnectionSettings {
pub host: String,
pub port: u16,
pub username: String,
pub password: String,
pub database: String,
pub additional_params: Option<HashMap<String, String>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct Database {
#[serde(rename = "templateHash")]
pub template_hash: TemplateHash,
pub config: ConnectionSettings,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct GetTestDbResponse {
pub database: Database,
pub id: i32,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct TemplateRequest {
pub hash: TemplateHash,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct InitializeTemplateResponse {
pub database: Database,
}
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
pub(crate) struct TemplateHash(u64);
impl TemplateHash {
pub const fn new(id: u64) -> Self {
TemplateHash(id)
}
pub fn from_hash(hashable: impl Hash) -> Self {
let mut hasher = Xxh64::new(0);
hashable.hash(&mut hasher);
let hash = hasher.finish();
TemplateHash(hash)
}
}
impl Display for TemplateHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:016x}", self.0)
}
}
impl Serialize for TemplateHash {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl FromStr for TemplateHash {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
u64::from_str_radix(s, 16).map(TemplateHash::new)
}
}
impl<'de> Deserialize<'de> for TemplateHash {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct TemplateIdVisitor;
impl<'de> serde::de::Visitor<'de> for TemplateIdVisitor {
type Value = TemplateHash;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string containing a u64 value as hexadecimal digits")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
u64::from_str_radix(v, 16)
.map(TemplateHash::new)
.map_err(|_| {
serde::de::Error::custom("value is not a valid hexadecimal string")
})
}
}
deserializer.deserialize_str(TemplateIdVisitor)
}
}
mod tests {
#[allow(unused_imports)]
use crate::server_models::TemplateHash;
#[test]
fn test_template_hash_new() {
let hash = TemplateHash::new(67890);
assert_eq!(hash.0, 67890);
}
#[test]
fn test_to_string() {
let hash = TemplateHash::new(0x1234);
assert_eq!(hash.to_string(), "0000000000001234");
let hash = TemplateHash::new(255);
assert_eq!(hash.to_string(), "00000000000000ff");
let hash = TemplateHash::new(0);
assert_eq!(hash.to_string(), "0000000000000000");
}
#[test]
fn test_json_serialization() {
let hash = TemplateHash::new(0x1234);
let json = serde_json::to_string(&hash).unwrap();
assert_eq!(json, "\"0000000000001234\"");
let deserialized: TemplateHash = serde_json::from_str("\"0000000000005678\"").unwrap();
assert_eq!(deserialized.0, 0x5678);
}
#[test]
fn test_parse() {
let result = "12345678".parse::<TemplateHash>();
assert!(result.is_ok());
assert_eq!(result.unwrap().0, 0x12345678);
let result = "invalid".parse::<TemplateHash>();
assert!(result.is_err());
}
}