use std::marker::PhantomData;
use crate::schema::{
self,
datum::OwnedDatumList,
entity::{
Entity, EntityID, EntityPart, EntityPartList, EntityPartVisitor, EntityRef,
EntityRefDatumList,
},
};
use crate::DBResult;
#[derive(Debug)]
pub struct IPEntityID<OE: Entity>(pub i64, PhantomData<OE>);
impl<OE: Entity> Clone for IPEntityID<OE> {
fn clone(&self) -> Self {
*self
}
}
impl<OE: Entity> Copy for IPEntityID<OE> {}
impl<OE: Entity> PartialEq for IPEntityID<OE> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<OE: Entity> Eq for IPEntityID<OE> {}
impl<OE: Entity> Ord for IPEntityID<OE> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<OE: Entity> PartialOrd for IPEntityID<OE> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<OE: Entity> std::hash::Hash for IPEntityID<OE> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state)
}
}
impl<OE: Entity> schema::datum::Datum for IPEntityID<OE> {
fn sql_type() -> &'static str {
i64::sql_type()
}
fn bind_to(&self, stmt: &mut crate::db::StatementContext, index: i32) -> DBResult<()> {
self.0.bind_to(stmt, index)
}
fn build_from(
adata: schema::relation::RelationData,
stmt: &mut crate::db::StatementRow,
index: &mut i32,
) -> DBResult<Self>
where
Self: Sized,
{
Ok(Self(i64::build_from(adata, stmt, index)?, PhantomData))
}
fn accept_discriminator(d: &mut impl schema::datum::DatumDiscriminator)
where
Self: Sized,
{
d.visit_entity_id::<IPEntity<OE>>();
}
fn accept_discriminator_ref(&self, d: &mut impl schema::datum::DatumDiscriminatorRef)
where
Self: Sized,
{
d.visit_entity_id::<IPEntity<OE>>(self);
}
}
impl<OE: Entity> schema::datum::OwnedDatum for IPEntityID<OE> {
type RefData<'a> = Self;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl<OE: Entity> schema::datum::BorrowedDatum<'_, IPEntityID<OE>> for IPEntityID<OE> {
fn as_owned(&self) -> Self {
*self
}
}
impl<OE: Entity> EntityID for IPEntityID<OE> {
type Entity = IPEntity<OE>;
fn from_raw(id: i64) -> Self {
Self(id, PhantomData)
}
fn into_raw(self) -> i64 {
self.0
}
}
pub struct IPEntityIDPart<OE: Entity>(PhantomData<OE>);
impl<OE: Entity> Clone for IPEntityIDPart<OE> {
fn clone(&self) -> Self {
*self
}
}
impl<OE: Entity> Copy for IPEntityIDPart<OE> {}
impl<OE: Entity> Default for IPEntityIDPart<OE> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<OE: Entity> EntityPart for IPEntityIDPart<OE> {
type Datum = IPEntityID<OE>;
type Entity = IPEntity<OE>;
fn desc() -> Option<&'static str> {
None
}
fn unique() -> bool {
false
}
fn part_name() -> &'static str {
"id"
}
fn get_datum(_: &Self::Entity) -> &Self::Datum {
unreachable!()
}
}
pub struct IPEntityPart<OE: Entity, OEP: EntityPart<Entity = OE>>(PhantomData<OEP>);
impl<OE: Entity, OEP: EntityPart<Entity = OE>> Clone for IPEntityPart<OE, OEP> {
fn clone(&self) -> Self {
Self(PhantomData)
}
}
impl<OE: Entity, OEP: EntityPart<Entity = OE>> Default for IPEntityPart<OE, OEP> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<OE: Entity, OEP: EntityPart<Entity = OE>> EntityPart for IPEntityPart<OE, OEP> {
type Datum = OEP::Datum;
type Entity = IPEntity<OE>;
fn desc() -> Option<&'static str> {
OEP::desc()
}
fn unique() -> bool {
OEP::unique()
}
fn part_name() -> &'static str {
OEP::part_name()
}
fn get_datum(from: &Self::Entity) -> &Self::Datum {
OEP::get_datum(&from.0)
}
}
pub struct IPEntityPartList<OE: Entity, OEPL: EntityPartList<Entity = OE>>(PhantomData<OEPL>);
struct PartListVisitorWrapper<'a, OE: Entity, EPV: EntityPartVisitor<Entity = IPEntity<OE>>>(
&'a mut EPV,
);
impl<OE: Entity, EPV: EntityPartVisitor<Entity = IPEntity<OE>>> EntityPartVisitor
for PartListVisitorWrapper<'_, OE, EPV>
{
type Entity = OE;
fn visit<EP: EntityPart<Entity = Self::Entity>>(&mut self) {
unreachable!()
}
fn visit_datum<EP: EntityPart<Entity = Self::Entity>>(
&mut self,
datum: &EP::Datum,
) -> DBResult<()> {
self.0.visit_datum::<IPEntityPart<OE, EP>>(datum)
}
fn visit_datum_mut<EP: EntityPart<Entity = Self::Entity>>(&mut self, datum: &mut EP::Datum) {
self.0.visit_datum_mut::<IPEntityPart<OE, EP>>(datum);
}
}
impl<OE: Entity, OEPL: EntityPartList<Entity = OE>> EntityPartList for IPEntityPartList<OE, OEPL> {
type Entity = IPEntity<OE>;
type ListHead = IPEntityPart<OE, OEPL::ListHead>;
type ListTail = IPEntityPartList<OE, OEPL::ListTail>;
type DatumList = OEPL::DatumList;
fn build_datum_list(stmt: &mut crate::db::StatementRow) -> DBResult<Self::DatumList> {
OEPL::build_datum_list(stmt)
}
fn build_datum_ref_list<'l, 'm>(
stmt: &'l mut crate::db::StatementRow,
) -> DBResult<<Self::DatumList as OwnedDatumList>::RefList<'m>>
where
'l: 'm,
{
OEPL::build_datum_ref_list(stmt)
}
fn accept_part_visitor(
visitor: &mut impl schema::entity::EntityPartVisitor<Entity = Self::Entity>,
) {
if !OEPL::IS_EMPTY {
visitor.visit::<Self::ListHead>();
Self::ListTail::accept_part_visitor(visitor);
}
}
fn accept_part_visitor_ref(
datum_list: &Self::DatumList,
visitor: &mut impl schema::entity::EntityPartVisitor<Entity = Self::Entity>,
) -> DBResult<()> {
OEPL::accept_part_visitor_ref(datum_list, &mut PartListVisitorWrapper(visitor))
}
}
#[derive(Debug)]
pub struct IPEntity<OE: Entity>(pub OE);
lazy_static::lazy_static! {
static ref IP_NAME_MAP: std::sync::RwLock<std::collections::HashMap<&'static str, &'static str>> = {
std::sync::RwLock::new(std::collections::HashMap::new())
};
}
pub struct IPERef<'l, OE: Entity> {
data: OE::ERef<'l>,
}
impl<'l, OE: Entity> IPERef<'l, OE> {
pub fn new(data: OE::ERef<'l>) -> Self {
Self { data }
}
}
impl<OE: Entity> Clone for IPERef<'_, OE> {
fn clone(&self) -> Self {
*self
}
}
impl<OE: Entity> Copy for IPERef<'_, OE> {}
impl<'l, OE: Entity> EntityRef<'l> for IPERef<'l, OE> {
type Entity = IPEntity<OE>;
fn as_entity(&self) -> Self::Entity {
IPEntity(self.data.as_entity())
}
fn as_borrowed_list<'r>(&self) -> EntityRefDatumList<'r, OE>
where
'l: 'r,
{
todo!()
}
fn from_borrowed_list<'r>(_l: EntityRefDatumList<'r, OE>) -> Self
where
'r: 'l,
{
todo!()
}
}
impl<OE: Entity> Entity for IPEntity<OE> {
type ID = IPEntityID<OE>;
type Parts = IPEntityPartList<OE, OE::Parts>;
type Keys = IPEntityPartList<OE, OE::Keys>;
type IDPart = IPEntityIDPart<OE>;
type ERef<'a>
= IPERef<'a, OE>
where
Self: Sized;
fn as_ref(&self) -> Self::ERef<'_>
where
Self: Sized,
{
IPERef {
data: self.0.as_ref(),
}
}
fn entity_name() -> &'static str {
let nmap = IP_NAME_MAP.read().unwrap();
if let Some(ename) = nmap.get(OE::entity_name()) {
ename
} else {
drop(nmap);
let mut nwmap = IP_NAME_MAP.write().unwrap();
let ename: &'static str =
Box::leak(format!("_IP_{}", OE::entity_name()).into_boxed_str());
nwmap.insert(OE::entity_name(), ename);
ename
}
}
fn build(values: <Self::Parts as EntityPartList>::DatumList) -> Self {
Self(OE::build(values))
}
fn accept_part_visitor(visitor: &mut impl schema::entity::EntityPartVisitor<Entity = Self>) {
Self::Parts::accept_part_visitor(visitor)
}
fn accept_part_visitor_ref(
&self,
visitor: &mut impl schema::entity::EntityPartVisitor<Entity = Self>,
) -> DBResult<()> {
self.0
.accept_part_visitor_ref(&mut PartListVisitorWrapper(visitor))
}
fn accept_part_visitor_mut(
&mut self,
visitor: &mut impl schema::entity::EntityPartVisitor<Entity = Self>,
) {
self.0
.accept_part_visitor_ref(&mut PartListVisitorWrapper(visitor))
.expect("migration accept_part_visitor_mut failed");
}
}