Skip to main content

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}