triblespace_core/id.rs
1//! Identifier utilities and ownership mechanisms for Trible Space.
2//!
3//! For a deeper discussion see the [Identifiers](../book/src/deep-dive/identifiers.md) chapter of the Tribles Book.
4
5/// Fast Unsafe Compressible ID generation.
6pub mod fucid;
7/// Random Number Generated ID generation.
8pub mod rngid;
9/// Universal Forgettable Ordered ID generation.
10pub mod ufoid;
11
12use std::borrow::Borrow;
13use std::cell::RefCell;
14use std::convert::TryInto;
15use std::fmt::Display;
16use std::fmt::LowerHex;
17use std::fmt::UpperHex;
18use std::hash::Hash;
19use std::marker::PhantomData;
20use std::mem;
21use std::num::NonZero;
22use std::ops::Deref;
23
24use hex::FromHex;
25
26/// Re-export of [`fucid::fucid`].
27pub use fucid::fucid;
28/// Re-export of [`fucid::FUCIDsource`].
29pub use fucid::FUCIDsource;
30/// Alias for [`rngid`] — generates a random 128-bit identifier.
31pub use rngid::rngid as genid;
32/// Re-export of [`rngid::rngid`].
33pub use rngid::rngid;
34/// Re-export of [`ufoid::ufoid`].
35pub use ufoid::ufoid;
36
37use crate::patch::Entry;
38use crate::patch::IdentitySchema;
39use crate::patch::PATCH;
40use crate::prelude::valueschemas::GenId;
41use crate::query::Constraint;
42use crate::query::ContainsConstraint;
43use crate::query::Variable;
44use crate::value::RawValue;
45use crate::value::VALUE_LEN;
46
47thread_local!(static OWNED_IDS: IdOwner = IdOwner::new());
48
49/// The length of a 128bit abstract identifier in bytes.
50pub const ID_LEN: usize = 16;
51
52/// Represents a 16 byte abstract identifier.
53pub type RawId = [u8; ID_LEN];
54
55/// Converts a 16 byte [RawId] reference into an 32 byte [RawValue].
56pub(crate) fn id_into_value(id: &RawId) -> RawValue {
57 let mut data = [0; VALUE_LEN];
58 data[16..32].copy_from_slice(id);
59 data
60}
61
62/// Converts a 32 byte [RawValue] reference into an 16 byte [RawId].
63/// Returns `None` if the value is not in the canonical ID format,
64/// i.e. the first 16 bytes are all zero.
65pub(crate) fn id_from_value(id: &RawValue) -> Option<RawId> {
66 if id[0..16] != [0; 16] {
67 return None;
68 }
69 let id = id[16..32].try_into().unwrap();
70 Some(id)
71}
72
73/// Represents a unique abstract 128 bit identifier.
74/// As we do not allow for all zero `nil` IDs,
75/// `Option<Id>` benefits from Option nieche optimizations.
76///
77/// Note that it has an alignment of 1, and can be referenced as a `[u8; 16]` [RawId].
78#[derive(Copy, Clone, Debug, PartialEq, Eq)]
79#[repr(C, packed(1))]
80pub struct Id {
81 inner: NonZero<u128>,
82}
83
84impl Id {
85 /// Creates a new [`Id`] from a [RawId] 16 byte array.
86 pub const fn new(id: RawId) -> Option<Self> {
87 unsafe { std::mem::transmute::<RawId, Option<Id>>(id) }
88 }
89
90 /// Parses a hexadecimal identifier string into an [`Id`].
91 ///
92 /// Returns `None` if the input is not valid hexadecimal or represents the
93 /// nil identifier (all zero bytes).
94 pub fn from_hex(hex: &str) -> Option<Self> {
95 let raw = <RawId as FromHex>::from_hex(hex).ok()?;
96 Id::new(raw)
97 }
98
99 /// Forces the creation of an [`Id`] from a [RawId] without checking for nil.
100 ///
101 /// # Safety
102 ///
103 /// The caller must ensure that `id` is not the nil value of all zero bytes.
104 pub const unsafe fn force(id: RawId) -> Self {
105 std::mem::transmute::<RawId, Id>(id)
106 }
107
108 /// Transmutes a reference to a [RawId] into a reference to an [`Id`].
109 /// Returns `None` if the referenced RawId is nil (all zero).
110 pub fn as_transmute_raw(id: &RawId) -> Option<&Self> {
111 if *id == [0; 16] {
112 None
113 } else {
114 Some(unsafe { std::mem::transmute::<&RawId, &Id>(id) })
115 }
116 }
117
118 /// Takes ownership of this Id from the current write context (i.e. thread).
119 /// Returns `None` if this Id was not found, because it is not associated with this
120 /// write context, or because it is currently aquired.
121 pub fn aquire(&self) -> Option<ExclusiveId> {
122 OWNED_IDS.with(|owner| owner.take(self))
123 }
124
125 /// Returns the raw 16-byte representation of this identifier.
126 ///
127 /// This is `const` so schema identifiers can be composed at compile time.
128 pub const fn raw(self) -> RawId {
129 // SAFETY: `Id` is a transparent 16-byte wrapper around a non-zero 128-bit
130 // integer. Its representation matches `RawId` by construction, as
131 // `Id::new` already transmutes from `RawId` to `Option<Id>`.
132 unsafe { std::mem::transmute::<Id, RawId>(self) }
133 }
134}
135
136impl PartialOrd for Id {
137 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
138 Some(self.cmp(other))
139 }
140}
141
142impl Ord for Id {
143 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
144 let s: &RawId = self;
145 let o: &RawId = other;
146 Ord::cmp(s, o)
147 }
148}
149
150impl Hash for Id {
151 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
152 let s: &RawId = self;
153 Hash::hash(s, state);
154 }
155}
156
157impl Deref for Id {
158 type Target = RawId;
159
160 fn deref(&self) -> &Self::Target {
161 unsafe { std::mem::transmute::<&Id, &RawId>(self) }
162 }
163}
164
165impl Borrow<RawId> for Id {
166 fn borrow(&self) -> &RawId {
167 self
168 }
169}
170
171impl AsRef<RawId> for Id {
172 fn as_ref(&self) -> &RawId {
173 self
174 }
175}
176
177impl AsRef<[u8]> for Id {
178 fn as_ref(&self) -> &[u8] {
179 &self[..]
180 }
181}
182
183impl From<Id> for RawId {
184 fn from(id: Id) -> Self {
185 *id
186 }
187}
188
189impl From<Id> for RawValue {
190 fn from(id: Id) -> Self {
191 let raw: RawId = id.into();
192 id_into_value(&raw)
193 }
194}
195
196impl Display for Id {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 write!(f, "Id({self:X})")
199 }
200}
201
202impl LowerHex for Id {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 for byte in &self[..] {
205 write!(f, "{byte:02x}")?;
206 }
207 Ok(())
208 }
209}
210
211impl UpperHex for Id {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 for byte in &self[..] {
214 write!(f, "{byte:02X}")?;
215 }
216 Ok(())
217 }
218}
219
220impl From<Id> for uuid::Uuid {
221 fn from(id: Id) -> Self {
222 let id: &RawId = &id;
223 uuid::Uuid::from_slice(id).unwrap()
224 }
225}
226
227/// Error returned when converting a nil (all-zero) UUID into an [`Id`].
228#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
229pub struct NilUuidError;
230
231impl TryFrom<uuid::Uuid> for Id {
232 type Error = NilUuidError;
233
234 fn try_from(id: uuid::Uuid) -> Result<Self, NilUuidError> {
235 let bytes = id.into_bytes();
236 Id::new(bytes).ok_or(NilUuidError)
237 }
238}
239
240impl std::fmt::Display for NilUuidError {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 write!(
243 f,
244 "UUID conversion failed: the UUID is nil (all zero bytes)"
245 )
246 }
247}
248
249impl std::error::Error for NilUuidError {}
250
251#[doc(hidden)]
252pub use hex_literal::hex as _hex_literal_hex;
253
254/// Creates an [`Id`] from a hex string literal.
255///
256/// # Example
257/// ```
258/// use triblespace_core::id::id_hex;
259/// let id = id_hex!("7D06820D69947D76E7177E5DEA4EA773");
260/// ```
261#[macro_export]
262macro_rules! id_hex {
263 ( $data:expr ) => {
264 $crate::id::Id::new($crate::id::_hex_literal_hex!($data)).unwrap()
265 };
266}
267
268/// Re-export of the [`id_hex!`] macro for use in other modules.
269pub use id_hex;
270
271/// Represents an ID that can only be used by a single writer at a time.
272///
273/// [`ExclusiveId`]s are associated with one owning context (typically a thread) at a time.
274/// Because they are `Send` and `!Sync`, they can be passed between contexts, but not used concurrently.
275/// This makes use of Rust's borrow checker to enforce a weaker form of software transactional memory (STM) without rollbacks - as these are not an issue with the heavy use of copy-on-write data structures.
276///
277/// They are automatically associated with the thread they are dropped from, which can be used in queries via the [local_ids] constraint.
278/// You can also make use of explicit [`IdOwner`] containers to store them when not actively used in a transaction.
279///
280/// Most methods defined on [`ExclusiveId`] are low-level primitives meant to be used for the implementation of new ownership management strategies,
281/// such as a transactional database that tracks checked out IDs for ownership, or distributed ledgers like blockchains.
282///
283#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
284#[repr(transparent)]
285pub struct ExclusiveId {
286 /// The underlying identifier.
287 pub id: Id,
288 // Make sure that the type can't be syntactically initialized.
289 // Also make sure that we don't get auto impl of Send and Sync
290 _private: PhantomData<*const ()>,
291}
292
293unsafe impl Send for ExclusiveId {}
294
295impl ExclusiveId {
296 /// Forces a regular (read-only) [`Id`] to become a writable [`ExclusiveId`].
297 ///
298 /// This is a low-level primitive that is meant to be used for the implementation of new ownership management strategies,
299 /// such as a transactional database that tracks checked out IDs for ownership, or distributed ledgers like blockchains.
300 ///
301 /// This should be done with care, as it allows scenarios where multiple writers can create conflicting information for the same ID.
302 /// Similar caution should be applied when using the `force_ref` and `forget` methods.
303 ///
304 /// # Arguments
305 ///
306 /// * `id` - The [`Id`] to be forced into an [`ExclusiveId`].
307 pub fn force(id: Id) -> Self {
308 Self {
309 id,
310 _private: PhantomData,
311 }
312 }
313
314 /// Safely transmutes a reference to an [`Id`] into a reference to an [`ExclusiveId`].
315 ///
316 /// Similar caution should be applied when using the `force` method.
317 ///
318 /// # Arguments
319 ///
320 /// * `id` - A reference to the [`Id`] to be transmuted.
321 pub fn force_ref(id: &Id) -> &Self {
322 unsafe { std::mem::transmute(id) }
323 }
324
325 /// Releases the [`ExclusiveId`], returning the underlying [`Id`].
326 ///
327 /// # Returns
328 ///
329 /// The underlying [`Id`].
330 pub fn release(self) -> Id {
331 let id = self.id;
332 mem::drop(self);
333 id
334 }
335
336 /// Forgets the [`ExclusiveId`], leaking ownership of the underlying [`Id`], while returning it.
337 ///
338 /// This is not as potentially problematic as [force](ExclusiveId::force), because it prevents further writes with the [`ExclusiveId`], thus avoiding potential conflicts.
339 ///
340 /// # Returns
341 ///
342 /// The underlying [`Id`].
343 pub fn forget(self) -> Id {
344 let id = self.id;
345 mem::forget(self);
346 id
347 }
348}
349
350impl Drop for ExclusiveId {
351 fn drop(&mut self) {
352 OWNED_IDS.with(|ids| {
353 ids.force_insert(self);
354 });
355 }
356}
357
358impl Deref for ExclusiveId {
359 type Target = Id;
360
361 fn deref(&self) -> &Self::Target {
362 &self.id
363 }
364}
365
366impl Borrow<RawId> for ExclusiveId {
367 fn borrow(&self) -> &RawId {
368 self
369 }
370}
371
372impl Borrow<Id> for ExclusiveId {
373 fn borrow(&self) -> &Id {
374 self
375 }
376}
377
378impl AsRef<Id> for ExclusiveId {
379 fn as_ref(&self) -> &Id {
380 self
381 }
382}
383
384impl AsRef<ExclusiveId> for ExclusiveId {
385 fn as_ref(&self) -> &ExclusiveId {
386 self
387 }
388}
389
390impl AsRef<RawId> for ExclusiveId {
391 fn as_ref(&self) -> &RawId {
392 self
393 }
394}
395
396impl AsRef<[u8]> for ExclusiveId {
397 fn as_ref(&self) -> &[u8] {
398 &self[..]
399 }
400}
401
402impl Display for ExclusiveId {
403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 let id: &Id = self;
405 write!(f, "ExclusiveId({id:X})")
406 }
407}
408
409/// A constraint that checks if a variable is an [`ExclusiveId`] associated with the current write context (i.e. thread).
410pub fn local_ids(v: Variable<GenId>) -> impl Constraint<'static> {
411 OWNED_IDS.with(|owner| owner.has(v))
412}
413
414/// A container for [`ExclusiveId`]s, allowing for explicit ownership management.
415/// There is an implicit [`IdOwner`] for each thread, to which [`ExclusiveId`]s are associated when they are dropped,
416/// and which can be queried via the [local_ids] constraint.
417///
418/// # Example
419///
420/// ```
421/// use triblespace_core::id::{IdOwner, ExclusiveId, fucid};
422/// let mut owner = IdOwner::new();
423/// let exclusive_id = fucid();
424/// let id = owner.insert(exclusive_id);
425///
426/// assert!(owner.owns(&id));
427/// assert_eq!(owner.take(&id), Some(ExclusiveId::force(id)));
428/// assert!(!owner.owns(&id));
429/// ```
430///
431pub struct IdOwner {
432 owned_ids: RefCell<PATCH<ID_LEN, IdentitySchema, ()>>,
433}
434
435/// An [`ExclusiveId`] that is associated with an [`IdOwner`].
436/// It is automatically returned to the [`IdOwner`] when dropped.
437pub struct OwnedId<'a> {
438 /// The underlying identifier.
439 pub id: Id,
440 owner: &'a IdOwner,
441}
442
443impl Default for IdOwner {
444 fn default() -> Self {
445 Self::new()
446 }
447}
448
449impl IdOwner {
450 /// Creates a new [`IdOwner`].
451 ///
452 /// This is typically not necessary, as each thread has an implicit [`IdOwner`] associated with it.
453 ///
454 /// # Returns
455 ///
456 /// A new [`IdOwner`].
457 pub fn new() -> Self {
458 Self {
459 owned_ids: RefCell::new(PATCH::<ID_LEN, IdentitySchema, ()>::new()),
460 }
461 }
462
463 /// Inserts an [`ExclusiveId`] into the [`IdOwner`], returning the underlying [`Id`].
464 ///
465 /// # Arguments
466 ///
467 /// * `id` - The [`ExclusiveId`] to be inserted.
468 ///
469 /// # Returns
470 ///
471 /// The underlying [`Id`].
472 pub fn insert(&mut self, id: ExclusiveId) -> Id {
473 self.force_insert(&id);
474 id.forget()
475 }
476
477 /// Defers inserting an [`ExclusiveId`] into the [`IdOwner`], returning an [`OwnedId`].
478 /// The [`OwnedId`] will return the [`ExclusiveId`] to the [`IdOwner`] when dropped.
479 /// This is useful if you generated an [`ExclusiveId`] that you want to use temporarily,
480 /// but want to make sure it is returned to the [`IdOwner`] when you are done.
481 ///
482 /// # Arguments
483 ///
484 /// * `id` - The [`ExclusiveId`] to be inserted.
485 ///
486 /// # Returns
487 ///
488 /// An [`OwnedId`] that will return the [`ExclusiveId`] to the [`IdOwner`] when dropped.
489 ///
490 /// # Example
491 ///
492 /// ```
493 /// use triblespace_core::prelude::*;
494 /// use valueschemas::ShortString;
495 /// use triblespace_core::id_hex;
496 ///
497 /// let mut owner = IdOwner::new();
498 /// let owned_id = owner.defer_insert(fucid());
499 /// let trible = Trible::new(&owned_id, &id_hex!("7830D7B3C2DCD44EB3FA68C93D06B973"), &ShortString::value_from("Hello, World!"));
500 /// ```
501 pub fn defer_insert(&self, id: ExclusiveId) -> OwnedId<'_> {
502 OwnedId {
503 id: id.forget(),
504 owner: self,
505 }
506 }
507
508 /// Forces an [`Id`] into the [`IdOwner`] as an [`ExclusiveId`].
509 ///
510 /// # Arguments
511 ///
512 /// * `id` - The [`Id`] to be forced into an [`ExclusiveId`].
513 pub fn force_insert(&self, id: &Id) {
514 let entry = Entry::new(id);
515 self.owned_ids.borrow_mut().insert(&entry);
516 }
517
518 /// Takes an [`Id`] from the [`IdOwner`], returning it as an [`ExclusiveId`].
519 ///
520 /// # Arguments
521 ///
522 /// * `id` - The [`Id`] to be taken.
523 ///
524 /// # Returns
525 ///
526 /// An [`ExclusiveId`] if the [`Id`] was found, otherwise `None`.
527 pub fn take(&self, id: &Id) -> Option<ExclusiveId> {
528 if self.owned_ids.borrow().has_prefix(id) {
529 self.owned_ids.borrow_mut().remove(id);
530 Some(ExclusiveId::force(*id))
531 } else {
532 None
533 }
534 }
535
536 /// Get an [`OwnedId`] from the [`IdOwner`].
537 /// The [`OwnedId`] will return the [`ExclusiveId`] to the [`IdOwner`] when dropped.
538 /// This is useful for temporary exclusive access to an [`Id`].
539 /// If you want to keep the [`Id`] for longer, you can use the `take` method,
540 /// but you will have to manually return it to the [`IdOwner`] when you are done.
541 ///
542 /// # Arguments
543 ///
544 /// * `id` - The [`Id`] to be taken.
545 ///
546 /// # Returns
547 ///
548 /// An [`OwnedId`] if the [`Id`] was found, otherwise `None`.
549 ///
550 /// # Example
551 ///
552 /// ```
553 /// use triblespace_core::id::{IdOwner, ExclusiveId, fucid};
554 /// let mut owner = IdOwner::new();
555 /// let exclusive_id = fucid();
556 /// let id = owner.insert(exclusive_id);
557 /// {
558 /// let mut owned_id = owner.borrow(&id).unwrap();
559 ///
560 /// assert_eq!(owned_id.id, id);
561 /// assert!(!owner.owns(&id));
562 /// }
563 /// assert!(owner.owns(&id));
564 /// ```
565 pub fn borrow<'a>(&'a self, id: &Id) -> Option<OwnedId<'a>> {
566 self.take(id).map(move |id| OwnedId {
567 id: id.forget(),
568 owner: self,
569 })
570 }
571
572 /// Checks if the [`IdOwner`] owns an [`Id`].
573 ///
574 /// # Arguments
575 ///
576 /// * `id` - The [`Id`] to be checked.
577 ///
578 /// # Returns
579 ///
580 /// `true` if the [`Id`] is owned by the [`IdOwner`], otherwise `false`.
581 pub fn owns(&self, id: &Id) -> bool {
582 self.owned_ids.borrow().has_prefix(id)
583 }
584}
585
586impl Deref for OwnedId<'_> {
587 type Target = ExclusiveId;
588
589 fn deref(&self) -> &Self::Target {
590 ExclusiveId::force_ref(&self.id)
591 }
592}
593
594impl Borrow<RawId> for OwnedId<'_> {
595 fn borrow(&self) -> &RawId {
596 self
597 }
598}
599
600impl Borrow<Id> for OwnedId<'_> {
601 fn borrow(&self) -> &Id {
602 self
603 }
604}
605
606impl Borrow<ExclusiveId> for OwnedId<'_> {
607 fn borrow(&self) -> &ExclusiveId {
608 self
609 }
610}
611
612impl AsRef<ExclusiveId> for OwnedId<'_> {
613 fn as_ref(&self) -> &ExclusiveId {
614 self
615 }
616}
617
618impl AsRef<Id> for OwnedId<'_> {
619 fn as_ref(&self) -> &Id {
620 self
621 }
622}
623
624impl AsRef<RawId> for OwnedId<'_> {
625 fn as_ref(&self) -> &RawId {
626 self
627 }
628}
629
630impl AsRef<[u8]> for OwnedId<'_> {
631 fn as_ref(&self) -> &[u8] {
632 &self[..]
633 }
634}
635
636impl Display for OwnedId<'_> {
637 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
638 let id: &Id = self;
639 write!(f, "OwnedId({id:X})")
640 }
641}
642
643impl<'a> Drop for OwnedId<'a> {
644 fn drop(&mut self) {
645 self.owner.force_insert(&(self.id));
646 }
647}
648
649impl ContainsConstraint<'static, GenId> for &IdOwner {
650 type Constraint =
651 <PATCH<ID_LEN, IdentitySchema, ()> as ContainsConstraint<'static, GenId>>::Constraint;
652
653 fn has(self, v: Variable<GenId>) -> Self::Constraint {
654 self.owned_ids.borrow().clone().has(v)
655 }
656}
657
658#[cfg(test)]
659mod tests {
660 use crate::examples::literature;
661 use crate::id::ExclusiveId;
662 use crate::prelude::*;
663 use crate::query::Query;
664 use crate::query::VariableContext;
665 use crate::value::schemas::genid::GenId;
666 use crate::value::schemas::shortstring::ShortString;
667
668 #[test]
669 fn id_formatting() {
670 let id: Id = id_hex!("7D06820D69947D76E7177E5DEA4EA773");
671 assert_eq!(format!("{id:x}"), "7d06820d69947d76e7177e5dea4ea773");
672 assert_eq!(format!("{id:X}"), "7D06820D69947D76E7177E5DEA4EA773");
673 }
674
675 #[test]
676 fn ns_local_ids() {
677 let mut kb = TribleSet::new();
678
679 {
680 let isaac = ufoid();
681 let jules = ufoid();
682 kb += entity! { &jules @
683 literature::firstname: "Jules",
684 literature::lastname: "Verne"
685 };
686 kb += entity! { &isaac @
687 literature::firstname: "Isaac",
688 literature::lastname: "Asimov"
689 };
690 }
691
692 let mut r: Vec<_> = find!(
693 (author: ExclusiveId, name: String),
694 and!(
695 local_ids(author),
696 pattern!(&kb, [
697 {?author @
698 literature::firstname: ?name
699 }])
700 )
701 )
702 .map(|(_, n)| n)
703 .collect();
704 r.sort();
705
706 assert_eq!(vec!["Isaac", "Jules"], r);
707 }
708
709 #[test]
710 fn ns_local_ids_bad_estimates_panics() {
711 let mut kb = TribleSet::new();
712
713 {
714 let isaac = ufoid();
715 let jules = ufoid();
716 kb += entity! { &jules @
717 literature::firstname: "Jules",
718 literature::lastname: "Verne"
719 };
720 kb += entity! { &isaac @
721 literature::firstname: "Isaac",
722 literature::lastname: "Asimov"
723 };
724 }
725
726 let mut ctx = VariableContext::new();
727 macro_rules! __local_find_context {
728 () => {
729 &mut ctx
730 };
731 }
732 let author = ctx.next_variable::<GenId>();
733 let name = ctx.next_variable::<ShortString>();
734
735 let base = and!(
736 local_ids(author),
737 pattern!(&kb, [{ ?author @ literature::firstname: ?name }])
738 );
739
740 let mut wrapper = crate::debug::query::EstimateOverrideConstraint::new(base);
741 wrapper.set_estimate(author.index, 100);
742 wrapper.set_estimate(name.index, 1);
743
744 let q: Query<_, _, _> =
745 Query::new(wrapper, |binding| Some(name.extract(binding).try_from_value::<String>().unwrap()));
746 let r: Vec<_> = q.collect();
747 assert_eq!(r, vec!["Isaac", "Jules"]);
748 }
749}