use crate::inventory::RustInventory;
use crate::inventory::TypeId;
use crate::lang::meta::{Docs, Emission, FileEmission, Visibility};
use crate::lang::types::{TypeInfo, TypeKind, TypePattern, WireIO};
use crate::wire::SerializationError;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::io::{Read, Write};
#[repr(transparent)]
#[allow(dead_code)]
#[derive(Debug, Default, PartialOrd, PartialEq, Eq, Copy, Clone)]
pub struct ApiVersion {
version: u64,
}
impl ApiVersion {
#[must_use]
pub const fn new(version: u64) -> Self {
Self { version }
}
#[must_use]
pub fn from_inventory(inventory: &RustInventory) -> Self {
let version = ApiHash::from(inventory).hash;
Self { version }
}
}
unsafe impl TypeInfo for ApiVersion {
const WIRE_SAFE: bool = true;
const RAW_SAFE: bool = true;
const ASYNC_SAFE: bool = true;
const SERVICE_SAFE: bool = false;
const SERVICE_CTOR_SAFE: bool = false;
fn id() -> TypeId {
TypeId::new(0xA6B162106C410FCAD91327A85E3FE14E)
}
fn kind() -> TypeKind {
TypeKind::TypePattern(TypePattern::APIVersion)
}
fn ty() -> crate::lang::types::Type {
crate::lang::types::Type {
emission: Emission::FileEmission(FileEmission::Common),
docs: Docs::empty(),
visibility: Visibility::Public,
name: "ApiVersion".to_string(),
kind: Self::kind(),
}
}
fn register(inventory: &mut impl crate::inventory::Inventory) {
inventory.register_type(Self::id(), Self::ty());
}
}
unsafe impl WireIO for ApiVersion {
fn write(&self, w: &mut impl Write) -> Result<(), SerializationError> {
<u64 as WireIO>::write(&self.version, w)
}
fn read(r: &mut impl Read) -> Result<Self, SerializationError> {
Ok(Self { version: u64::read(r)? })
}
fn live_size(&self) -> usize {
self.version.live_size()
}
}
impl From<RustInventory> for ApiVersion {
fn from(i: RustInventory) -> Self {
Self::from_inventory(&i)
}
}
pub struct ApiHash {
pub hash: u64,
pub hash_hex: String,
}
impl ApiHash {
#[must_use]
pub fn from(inventory: &RustInventory) -> Self {
let mut hasher = DefaultHasher::new();
let mut types: Vec<_> = inventory.types.iter().collect();
let mut functions: Vec<_> = inventory.functions.iter().collect();
let mut constants: Vec<_> = inventory.constants.iter().collect();
types.sort_by_key(|(id, _)| *id);
functions.sort_by_key(|(id, _)| *id);
constants.sort_by_key(|(id, _)| *id);
for t in types {
t.hash(&mut hasher);
}
for f in functions {
f.hash(&mut hasher);
}
for c in constants {
c.1.name.hash(&mut hasher);
c.1.value.hash(&mut hasher);
}
Self::new(hasher.finish())
}
#[must_use]
pub fn new(hash: u64) -> Self {
let hash_hex = format!("{hash:x}");
Self { hash, hash_hex }
}
#[must_use]
pub const fn hash(&self) -> u64 {
self.hash
}
#[must_use]
pub fn hash_hex(&self) -> &str {
self.hash_hex.as_str()
}
}
#[macro_export]
macro_rules! api_guard {
($f:tt) => {{
#[$crate::ffi]
pub fn __api_guard() -> $crate::pattern::api_guard::ApiVersion {
$f().into()
}
|x: &mut $crate::inventory::RustInventory| {
<__api_guard as $crate::lang::function::FunctionInfo>::register(x);
}
}};
}