use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fmt;
use std::marker::PhantomData;
use std::sync::Arc;
use serde::de::{self, DeserializeOwned, MapAccess};
use serde::ser;
use serde::{Deserialize, Serialize};
use crate::{
CacheEntry, Cache, DatabaseEntry, DatabaseLink, LinkOrEntity, READ_CONTEXT, WRITE_CONTEXT, type_name
};
pub fn serialize_link<T: DatabaseEntry + Serialize, S: ser::Serializer>(
instance: &T,
serializer: S,
) -> Result<S::Ok, S::Error> {
return WRITE_CONTEXT.with(|thread_context| {
match thread_context.get() {
Some(context) => {
let write_mode = {
let write_options = unsafe { &*context.write_options };
write_options.write_mode
};
match write_mode {
crate::WriteMode::Flat => return instance.serialize(serializer),
crate::WriteMode::Link => {
let file_path = match context.write(instance) {
Ok(file_path) => file_path,
Err(msg) => return Err(ser::Error::custom(msg)),
};
return DatabaseLink::new(
instance,
crate::checksum(file_path.as_path()),
)
.serialize(serializer);
}
};
}
None => {
return instance.serialize(serializer);
}
}
});
}
pub fn serialize_opt_link<T: DatabaseEntry + Serialize, S: ser::Serializer>(
instance: &Option<T>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match instance {
Some(inst) => return serialize_link(inst, serializer),
None => return None::<T>.serialize(serializer),
}
}
pub fn serialize_arc_link<T: DatabaseEntry + Serialize, S: ser::Serializer>(
instance: &Arc<T>,
serializer: S,
) -> Result<S::Ok, S::Error> {
return serialize_link(&**instance, serializer);
}
pub fn serialize_opt_arc_link<T: DatabaseEntry + Serialize, S: ser::Serializer>(
instance: &Option<Arc<T>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match instance {
Some(inst) => return serialize_link(&**inst, serializer),
None => return None::<Arc<T>>.serialize(serializer),
}
}
pub fn deserialize_link<'de, D, T: DatabaseEntry + DeserializeOwned>(
deserializer: D,
) -> Result<T, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<T: DatabaseEntry> {
phantom: PhantomData<T>,
}
impl<'de, T: DatabaseEntry + DeserializeOwned> de::Visitor<'de> for Visitor<T> {
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("either a Material or a DatabaseLink struct.")
}
fn visit_map<M>(self, visitor: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let link_or_instance: LinkOrEntity<T> =
Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor))?;
let instance: T = match link_or_instance {
LinkOrEntity::Entity(val) => {
val
}
LinkOrEntity::DatabaseLink(link) => {
let res: Result<T, std::io::Error> = READ_CONTEXT.with(|thread_context| {
match thread_context.get() {
Some(context) => {
let file_path = {
let dbm = unsafe {&mut *context.database_manager};
dbm.full_path_unchecked((type_name::<T>(), &link.name))
};
if let Some(mismatch) = link.test_for_checksum_mismatch(file_path) {
crate::RwInfo::log_checksum_mismatch(mismatch);
}
context.read(OsStr::new(&link.name))
},
None => {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"No database manager has been set. Therefore, it is not possible to resolve links.".to_string(),
))
}
}
});
match res {
Ok(val) => val,
Err(msg) => return Err(de::Error::custom(msg)),
}
}
};
return Ok(instance);
}
}
deserializer.deserialize_map(Visitor {
phantom: PhantomData,
})
}
pub fn deserialize_opt_link<
'de,
D,
T: DatabaseEntry + Send + Sync + 'static + DeserializeOwned,
>(
deserializer: D,
) -> Result<Option<T>, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<T> {
phantom: PhantomData<T>,
}
impl<'de, T: DatabaseEntry + Send + Sync + 'static + DeserializeOwned> de::Visitor<'de>
for Visitor<T>
{
type Value = Option<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("either a Material, a DatabaseLink or None.")
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
let instance = deserialize_link(deserializer)?;
return Ok(Some(instance));
}
fn visit_none<F>(self) -> Result<Self::Value, F>
where
F: de::Error,
{
return Ok(None);
}
}
let deserialized_instance = deserializer.deserialize_option(Visitor {
phantom: PhantomData,
})?;
return Ok(deserialized_instance);
}
pub fn deserialize_arc_link<'de, D, T: DatabaseEntry + Send + Sync + 'static + DeserializeOwned>(
deserializer: D,
) -> Result<Arc<T>, D::Error>
where
D: de::Deserializer<'de>,
{
fn read_cache<T: Send + Sync + DatabaseEntry + 'static>(
cache: &mut Cache,
link: &DatabaseLink,
) -> Option<Arc<T>> {
match cache.get_mut(&TypeId::of::<T>()) {
Some(name_map) => {
let mut remove_entry = false;
let instance = name_map
.get(OsStr::new(&link.name))
.map(|checksum_arc| {
let use_arc_instance = match checksum_arc.checksum {
Some(checksum_of_arc) => match link.checksum {
Some(checksum_of_file) => checksum_of_arc == checksum_of_file,
None => true,
},
None => true,
};
if use_arc_instance {
let arc_any = checksum_arc.arc.clone() as Arc<dyn Any + Send +Sync>;
arc_any.downcast::<T>().ok()
} else {
remove_entry = true;
None
}
})
.flatten();
if remove_entry {
let _ = name_map.remove(OsStr::new(&link.name));
}
return instance;
}
None => return None,
}
}
fn write_cache<T: Send + Sync + DatabaseEntry + 'static>(
cache: &mut Cache,
link: &DatabaseLink,
instance: Arc<dyn DatabaseEntry + Send + Sync + 'static>,
) -> () {
if !cache.contains_key(&TypeId::of::<T>()) {
cache.insert(TypeId::of::<T>(), HashMap::new());
}
let name_map = cache.get_mut(&TypeId::of::<T>()).unwrap(); let checksum_arc = CacheEntry {
arc: instance,
checksum: link.checksum,
};
name_map.insert(link.name.clone().into(), checksum_arc);
return;
}
struct VisitorArc<T> {
phantom: PhantomData<T>,
}
impl<'de, T: DatabaseEntry + Send + Sync + 'static + DeserializeOwned> de::Visitor<'de>
for VisitorArc<T>
{
type Value = Arc<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.write_str("either a type implementing DatabaseEntry or a DatabaseLink struct.")
}
fn visit_map<M>(self, visitor: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let link_or_instance: LinkOrEntity<T> =
Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor))?;
let instance: Self::Value = match link_or_instance {
LinkOrEntity::Entity(val) => {
Arc::new(val)
}
LinkOrEntity::DatabaseLink(link) => {
let res: std::io::Result<Arc<T>> = READ_CONTEXT.with(|thread_context| {
match thread_context.get() {
Some(context) => {
if let Some(arc) = read_cache(&mut unsafe {&mut *context.database_manager}.cache_mut(), &link) {
Ok(arc)
} else {
let instance: T = context.read(
OsStr::new(&link.name),
)?;
let arc = Arc::new(instance);
let file_path = {
let dbm = unsafe {&mut *context.database_manager};
dbm.full_path_unchecked((type_name::<T>(), &link.name))
};
if let Some(mismatch) = link.test_for_checksum_mismatch(file_path) {
crate::RwInfo::log_checksum_mismatch(mismatch);
}
write_cache::<T>(&mut unsafe {&mut *context.database_manager}.cache_mut(), &link, arc.clone());
Ok(arc)
}
},
None => {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"No database manager has been set. Therefore, it is not possible to resolve links.".to_string(),
))
}
}
});
match res {
Ok(val) => val,
Err(msg) => return Err(de::Error::custom(msg)),
}
}
};
return Ok(instance);
}
}
let deserialized_instance = deserializer.deserialize_map(VisitorArc {
phantom: PhantomData,
})?;
return Ok(deserialized_instance);
}
pub fn deserialize_opt_arc_link<
'de,
D,
T: DatabaseEntry + Send + Sync + 'static + DeserializeOwned,
>(
deserializer: D,
) -> Result<Option<Arc<T>>, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<T> {
phantom: PhantomData<T>,
}
impl<'de, T: DatabaseEntry + Send + Sync + 'static + DeserializeOwned> de::Visitor<'de>
for Visitor<T>
{
type Value = Option<Arc<T>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("either a Material, a DatabaseLink or None.")
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
let instance = deserialize_arc_link(deserializer)?;
return Ok(Some(instance));
}
fn visit_none<F>(self) -> Result<Self::Value, F>
where
F: de::Error,
{
return Ok(None);
}
}
let deserialized_instance = deserializer.deserialize_option(Visitor {
phantom: PhantomData,
})?;
return Ok(deserialized_instance);
}