1pub mod fucid;
6pub mod rngid;
7pub mod ufoid;
8
9use std::borrow::Borrow;
10use std::cell::RefCell;
11use std::convert::TryInto;
12use std::fmt::Display;
13use std::fmt::LowerHex;
14use std::fmt::UpperHex;
15use std::hash::Hash;
16use std::marker::PhantomData;
17use std::mem;
18use std::num::NonZero;
19use std::ops::Deref;
20
21use hex::FromHex;
22
23pub use fucid::fucid;
24pub use fucid::FUCIDsource;
25pub use rngid::rngid as genid;
26pub use rngid::rngid;
27pub use ufoid::ufoid;
28
29use crate::patch::Entry;
30use crate::patch::IdentitySchema;
31use crate::patch::PATCH;
32use crate::prelude::valueschemas::GenId;
33use crate::query::Constraint;
34use crate::query::ContainsConstraint;
35use crate::query::Variable;
36use crate::value::RawValue;
37use crate::value::VALUE_LEN;
38
39thread_local!(static OWNED_IDS: IdOwner = IdOwner::new());
40
41pub const ID_LEN: usize = 16;
43
44pub type RawId = [u8; ID_LEN];
46
47pub(crate) fn id_into_value(id: &RawId) -> RawValue {
49 let mut data = [0; VALUE_LEN];
50 data[16..32].copy_from_slice(id);
51 data
52}
53
54pub(crate) fn id_from_value(id: &RawValue) -> Option<RawId> {
58 if id[0..16] != [0; 16] {
59 return None;
60 }
61 let id = id[16..32].try_into().unwrap();
62 Some(id)
63}
64
65#[derive(Copy, Clone, Debug, PartialEq, Eq)]
71#[repr(C, packed(1))]
72pub struct Id {
73 inner: NonZero<u128>,
74}
75
76impl Id {
77 pub const fn new(id: RawId) -> Option<Self> {
79 unsafe { std::mem::transmute::<RawId, Option<Id>>(id) }
80 }
81
82 pub fn from_hex(hex: &str) -> Option<Self> {
87 let raw = <RawId as FromHex>::from_hex(hex).ok()?;
88 Id::new(raw)
89 }
90
91 pub const unsafe fn force(id: RawId) -> Self {
97 std::mem::transmute::<RawId, Id>(id)
98 }
99
100 pub fn as_transmute_raw(id: &RawId) -> Option<&Self> {
103 if *id == [0; 16] {
104 None
105 } else {
106 Some(unsafe { std::mem::transmute::<&RawId, &Id>(id) })
107 }
108 }
109
110 pub fn aquire(&self) -> Option<ExclusiveId> {
114 OWNED_IDS.with(|owner| owner.take(self))
115 }
116}
117
118impl PartialOrd for Id {
119 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
120 Some(self.cmp(other))
121 }
122}
123
124impl Ord for Id {
125 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
126 let s: &RawId = self;
127 let o: &RawId = other;
128 Ord::cmp(s, o)
129 }
130}
131
132impl Hash for Id {
133 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
134 let s: &RawId = self;
135 Hash::hash(s, state);
136 }
137}
138
139impl Deref for Id {
140 type Target = RawId;
141
142 fn deref(&self) -> &Self::Target {
143 unsafe { std::mem::transmute::<&Id, &RawId>(self) }
144 }
145}
146
147impl Borrow<RawId> for Id {
148 fn borrow(&self) -> &RawId {
149 self
150 }
151}
152
153impl AsRef<RawId> for Id {
154 fn as_ref(&self) -> &RawId {
155 self
156 }
157}
158
159impl AsRef<[u8]> for Id {
160 fn as_ref(&self) -> &[u8] {
161 &self[..]
162 }
163}
164
165impl From<Id> for RawId {
166 fn from(id: Id) -> Self {
167 *id
168 }
169}
170
171impl From<Id> for RawValue {
172 fn from(id: Id) -> Self {
173 let raw: RawId = id.into();
174 id_into_value(&raw)
175 }
176}
177
178impl Display for Id {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 write!(f, "Id({self:X})")
181 }
182}
183
184impl LowerHex for Id {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 for byte in &self[..] {
187 write!(f, "{byte:02x}")?;
188 }
189 Ok(())
190 }
191}
192
193impl UpperHex for Id {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 for byte in &self[..] {
196 write!(f, "{byte:02X}")?;
197 }
198 Ok(())
199 }
200}
201
202impl From<Id> for uuid::Uuid {
203 fn from(id: Id) -> Self {
204 let id: &RawId = &id;
205 uuid::Uuid::from_slice(id).unwrap()
206 }
207}
208
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
210pub struct NilUuidError;
211
212impl TryFrom<uuid::Uuid> for Id {
213 type Error = NilUuidError;
214
215 fn try_from(id: uuid::Uuid) -> Result<Self, NilUuidError> {
216 let bytes = id.into_bytes();
217 Id::new(bytes).ok_or(NilUuidError)
218 }
219}
220
221impl std::fmt::Display for NilUuidError {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 write!(
224 f,
225 "UUID conversion failed: the UUID is nil (all zero bytes)"
226 )
227 }
228}
229
230impl std::error::Error for NilUuidError {}
231
232#[doc(hidden)]
233pub use hex_literal::hex as _hex_literal_hex;
234
235#[macro_export]
243macro_rules! id_hex {
244 ( $data:expr ) => {
245 $crate::id::Id::new($crate::id::_hex_literal_hex!($data)).unwrap()
246 };
247}
248
249pub use id_hex;
250
251#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
264#[repr(transparent)]
265pub struct ExclusiveId {
266 pub id: Id,
267 _private: PhantomData<*const ()>,
270}
271
272unsafe impl Send for ExclusiveId {}
273
274impl ExclusiveId {
275 pub fn force(id: Id) -> Self {
287 Self {
288 id,
289 _private: PhantomData,
290 }
291 }
292
293 pub fn force_ref(id: &Id) -> &Self {
301 unsafe { std::mem::transmute(id) }
302 }
303
304 pub fn release(self) -> Id {
310 let id = self.id;
311 mem::drop(self);
312 id
313 }
314
315 pub fn forget(self) -> Id {
323 let id = self.id;
324 mem::forget(self);
325 id
326 }
327}
328
329impl Drop for ExclusiveId {
330 fn drop(&mut self) {
331 OWNED_IDS.with(|ids| {
332 ids.force_insert(self);
333 });
334 }
335}
336
337impl Deref for ExclusiveId {
338 type Target = Id;
339
340 fn deref(&self) -> &Self::Target {
341 &self.id
342 }
343}
344
345impl Borrow<RawId> for ExclusiveId {
346 fn borrow(&self) -> &RawId {
347 self
348 }
349}
350
351impl Borrow<Id> for ExclusiveId {
352 fn borrow(&self) -> &Id {
353 self
354 }
355}
356
357impl AsRef<Id> for ExclusiveId {
358 fn as_ref(&self) -> &Id {
359 self
360 }
361}
362
363impl AsRef<ExclusiveId> for ExclusiveId {
364 fn as_ref(&self) -> &ExclusiveId {
365 self
366 }
367}
368
369impl AsRef<RawId> for ExclusiveId {
370 fn as_ref(&self) -> &RawId {
371 self
372 }
373}
374
375impl AsRef<[u8]> for ExclusiveId {
376 fn as_ref(&self) -> &[u8] {
377 &self[..]
378 }
379}
380
381impl Display for ExclusiveId {
382 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
383 let id: &Id = self;
384 write!(f, "ExclusiveId({id:X})")
385 }
386}
387
388pub fn local_ids(v: Variable<GenId>) -> impl Constraint<'static> {
390 OWNED_IDS.with(|owner| owner.has(v))
391}
392
393pub struct IdOwner {
411 owned_ids: RefCell<PATCH<ID_LEN, IdentitySchema, ()>>,
412}
413
414pub struct OwnedId<'a> {
417 pub id: Id,
418 owner: &'a IdOwner,
419}
420
421impl Default for IdOwner {
422 fn default() -> Self {
423 Self::new()
424 }
425}
426
427impl IdOwner {
428 pub fn new() -> Self {
436 Self {
437 owned_ids: RefCell::new(PATCH::<ID_LEN, IdentitySchema, ()>::new()),
438 }
439 }
440
441 pub fn insert(&mut self, id: ExclusiveId) -> Id {
451 self.force_insert(&id);
452 id.forget()
453 }
454
455 pub fn defer_insert(&self, id: ExclusiveId) -> OwnedId<'_> {
480 OwnedId {
481 id: id.forget(),
482 owner: self,
483 }
484 }
485
486 pub fn force_insert(&self, id: &Id) {
492 let entry = Entry::new(id);
493 self.owned_ids.borrow_mut().insert(&entry);
494 }
495
496 pub fn take(&self, id: &Id) -> Option<ExclusiveId> {
506 if self.owned_ids.borrow().has_prefix(id) {
507 self.owned_ids.borrow_mut().remove(id);
508 Some(ExclusiveId::force(*id))
509 } else {
510 None
511 }
512 }
513
514 pub fn borrow<'a>(&'a self, id: &Id) -> Option<OwnedId<'a>> {
544 self.take(id).map(move |id| OwnedId {
545 id: id.forget(),
546 owner: self,
547 })
548 }
549
550 pub fn owns(&self, id: &Id) -> bool {
560 self.owned_ids.borrow().has_prefix(id)
561 }
562}
563
564impl Deref for OwnedId<'_> {
565 type Target = ExclusiveId;
566
567 fn deref(&self) -> &Self::Target {
568 ExclusiveId::force_ref(&self.id)
569 }
570}
571
572impl Borrow<RawId> for OwnedId<'_> {
573 fn borrow(&self) -> &RawId {
574 self
575 }
576}
577
578impl Borrow<Id> for OwnedId<'_> {
579 fn borrow(&self) -> &Id {
580 self
581 }
582}
583
584impl Borrow<ExclusiveId> for OwnedId<'_> {
585 fn borrow(&self) -> &ExclusiveId {
586 self
587 }
588}
589
590impl AsRef<ExclusiveId> for OwnedId<'_> {
591 fn as_ref(&self) -> &ExclusiveId {
592 self
593 }
594}
595
596impl AsRef<Id> for OwnedId<'_> {
597 fn as_ref(&self) -> &Id {
598 self
599 }
600}
601
602impl AsRef<RawId> for OwnedId<'_> {
603 fn as_ref(&self) -> &RawId {
604 self
605 }
606}
607
608impl AsRef<[u8]> for OwnedId<'_> {
609 fn as_ref(&self) -> &[u8] {
610 &self[..]
611 }
612}
613
614impl Display for OwnedId<'_> {
615 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
616 let id: &Id = self;
617 write!(f, "OwnedId({id:X})")
618 }
619}
620
621impl<'a> Drop for OwnedId<'a> {
622 fn drop(&mut self) {
623 self.owner.force_insert(&(self.id));
624 }
625}
626
627impl ContainsConstraint<'static, GenId> for &IdOwner {
628 type Constraint =
629 <PATCH<ID_LEN, IdentitySchema, ()> as ContainsConstraint<'static, GenId>>::Constraint;
630
631 fn has(self, v: Variable<GenId>) -> Self::Constraint {
632 self.owned_ids.borrow().clone().has(v)
633 }
634}
635
636#[cfg(test)]
637mod tests {
638 use crate::examples::literature;
639 use crate::id::ExclusiveId;
640 use crate::prelude::*;
641 use crate::query::Query;
642 use crate::query::VariableContext;
643 use crate::value::schemas::genid::GenId;
644 use crate::value::schemas::shortstring::ShortString;
645
646 #[test]
647 fn id_formatting() {
648 let id: Id = id_hex!("7D06820D69947D76E7177E5DEA4EA773");
649 assert_eq!(format!("{id:x}"), "7d06820d69947d76e7177e5dea4ea773");
650 assert_eq!(format!("{id:X}"), "7D06820D69947D76E7177E5DEA4EA773");
651 }
652
653 #[test]
654 fn ns_local_ids() {
655 let mut kb = TribleSet::new();
656
657 {
658 let isaac = ufoid();
659 let jules = ufoid();
660 kb += entity! { &jules @
661 literature::firstname: "Jules",
662 literature::lastname: "Verne"
663 };
664 kb += entity! { &isaac @
665 literature::firstname: "Isaac",
666 literature::lastname: "Asimov"
667 };
668 }
669
670 let mut r: Vec<_> = find!(
671 (author: ExclusiveId, name: String),
672 and!(
673 local_ids(author),
674 pattern!(&kb, [
675 {?author @
676 literature::firstname: ?name
677 }])
678 )
679 )
680 .map(|(_, n)| n)
681 .collect();
682 r.sort();
683
684 assert_eq!(vec!["Isaac", "Jules"], r);
685 }
686
687 #[test]
688 fn ns_local_ids_bad_estimates_panics() {
689 let mut kb = TribleSet::new();
690
691 {
692 let isaac = ufoid();
693 let jules = ufoid();
694 kb += entity! { &jules @
695 literature::firstname: "Jules",
696 literature::lastname: "Verne"
697 };
698 kb += entity! { &isaac @
699 literature::firstname: "Isaac",
700 literature::lastname: "Asimov"
701 };
702 }
703
704 let mut ctx = VariableContext::new();
705 macro_rules! __local_find_context {
706 () => {
707 &mut ctx
708 };
709 }
710 let author = ctx.next_variable::<GenId>();
711 let name = ctx.next_variable::<ShortString>();
712
713 let base = and!(
714 local_ids(author),
715 pattern!(&kb, [{ ?author @ literature::firstname: ?name }])
716 );
717
718 let mut wrapper = crate::debug::query::EstimateOverrideConstraint::new(base);
719 wrapper.set_estimate(author.index, 100);
720 wrapper.set_estimate(name.index, 1);
721
722 let q: Query<_, _, _> =
723 Query::new(wrapper, |binding| String::from_value(name.extract(binding)));
724 let r: Vec<_> = q.collect();
725 assert_eq!(r, vec!["Isaac", "Jules"]);
726 }
727}