rotonda_macros/
lib.rs

1extern crate proc_macro;
2
3mod maps;
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use std::iter::Iterator;
8use syn::parse_macro_input;
9
10#[proc_macro_attribute]
11pub fn stride_sizes(attr: TokenStream, input: TokenStream) -> TokenStream {
12    // The arguments for the macro invocation
13    let attrs = parse_macro_input!(attr as syn::ExprTuple);
14
15    let attrs = attrs.elems.iter().collect::<Vec<_>>();
16
17    let input = parse_macro_input!(input as syn::ItemStruct);
18    let type_name = &input.ident;
19    let ip_af = match attrs[0] {
20        syn::Expr::Path(t) => t,
21        _ => panic!("Expected Family Type"),
22    };
23    let prefixes_all_len;
24    let all_len;
25    let prefixes_buckets_name: syn::Ident;
26    // let prefix_store_bits;
27    let get_root_prefix_set;
28
29    // The name of the Struct that we're going to generate
30    // We'll prepend it with the name of the TreeBitMap struct
31    // that the user wants, so that our macro is a little bit
32    // more hygienic, and the user can create multiple types
33    // of TreeBitMap structs with different stride sizes.
34    let buckets_name = if ip_af.path.is_ident("IPv4") {
35        format_ident!("{}NodeBuckets4", type_name)
36    } else {
37        format_ident!("{}NodeBuckets6", type_name)
38    };
39    let store_bits = if ip_af.path.is_ident("IPv4") {
40        all_len = (0..=32_u8).collect::<Vec<_>>();
41        prefixes_all_len = (0..=32_u8)
42            .map(|l| format_ident!("p{}", l))
43            .collect::<Vec<_>>();
44        prefixes_buckets_name = format_ident!("PrefixBuckets4");
45        // prefix_store_bits = format_ident!("prefix_store_bits_4");
46        get_root_prefix_set = quote! {
47            fn get_root_prefix_set(&self, len: u8) -> &'_ PrefixSet<IPv4, M> {
48                [
49                    &self.p0, &self.p1, &self.p2, &self.p3, &self.p4, &self.p5, &self.p6, &self.p7, &self.p8,
50                    &self.p9, &self.p10, &self.p11, &self.p12, &self.p13, &self.p14, &self.p15, &self.p16,
51                    &self.p17, &self.p18, &self.p19, &self.p20, &self.p21, &self.p22, &self.p23, &self.p24,
52                    &self.p25, &self.p26, &self.p27, &self.p28, &self.p29, &self.p30, &self.p31, &self.p32
53                ][len as usize]
54            }
55        };
56        crate::maps::node_buckets_map_v4()
57    } else {
58        all_len = (0..=128_u8).collect::<Vec<_>>();
59        prefixes_all_len = (0..=128_u8)
60            .map(|l| format_ident!("p{}", l))
61            .collect::<Vec<_>>();
62
63        prefixes_buckets_name = format_ident!("PrefixBuckets6");
64        // prefix_store_bits = format_ident!("prefix_store_bits_6");
65        get_root_prefix_set = quote! {
66            fn get_root_prefix_set(&self, len: u8) -> &'_ PrefixSet<IPv6, M> {
67                [
68                    &self.p0, &self.p1, &self.p2, &self.p3, &self.p4, &self.p5, &self.p6, &self.p7, &self.p8,
69                    &self.p9, &self.p10, &self.p11, &self.p12, &self.p13, &self.p14, &self.p15, &self.p16,
70                    &self.p17, &self.p18, &self.p19, &self.p20, &self.p21, &self.p22, &self.p23, &self.p24,
71                    &self.p25, &self.p26, &self.p27, &self.p28, &self.p29, &self.p30, &self.p31, &self.p32,
72                    &self.p33, &self.p34, &self.p35, &self.p36, &self.p37, &self.p38, &self.p39, &self.p40,
73                    &self.p41, &self.p42, &self.p43, &self.p44, &self.p45, &self.p46, &self.p47, &self.p48,
74                    &self.p49, &self.p50, &self.p51, &self.p52, &self.p53, &self.p54, &self.p55, &self.p56,
75                    &self.p57, &self.p58, &self.p59, &self.p60, &self.p61, &self.p62, &self.p63, &self.p64,
76                    &self.p65, &self.p66, &self.p67, &self.p68, &self.p69, &self.p70, &self.p71, &self.p72,
77                    &self.p73, &self.p74, &self.p75, &self.p76, &self.p77, &self.p78, &self.p79, &self.p80,
78                    &self.p81, &self.p82, &self.p83, &self.p84, &self.p85, &self.p86, &self.p87, &self.p88,
79                    &self.p89, &self.p90, &self.p91, &self.p92, &self.p93, &self.p94, &self.p95, &self.p96,
80                    &self.p97, &self.p98, &self.p99, &self.p100, &self.p101, &self.p102, &self.p103, &self.p104,
81                    &self.p105, &self.p106, &self.p107, &self.p108, &self.p109, &self.p110, &self.p111, &self.p112,
82                    &self.p113, &self.p114, &self.p115, &self.p116, &self.p117, &self.p118, &self.p119, &self.p120,
83                    &self.p121, &self.p122, &self.p123, &self.p124, &self.p125, &self.p126, &self.p127, &self.p128
84                    ][len as usize]
85            }
86        };
87        crate::maps::node_buckets_map_v6()
88    };
89
90    let mut strides_num: Vec<u8> = vec![];
91    let mut strides = vec![];
92    let mut strides_all_len = vec![];
93    let mut strides_all_len_accu: Vec<u8> = vec![];
94    let mut strides_all_len_level = vec![];
95    let mut strides_len3 = vec![];
96    let mut strides_len3_l = vec![];
97    let mut strides_len4 = vec![];
98    let mut strides_len4_l = vec![];
99    let mut strides_len5 = vec![];
100    let mut strides_len5_l = vec![];
101
102    let mut s_accu = 0_u8;
103
104    let attrs_s = match attrs[1] {
105        syn::Expr::Array(arr) => arr,
106        _ => panic!("Expected an array"),
107    };
108    let strides_len = attrs_s.elems.len() as u8;
109    let first_stride_size = &attrs_s.elems[0];
110
111    for (len, stride) in attrs_s.elems.iter().enumerate() {
112        strides_all_len.push(format_ident!("l{}", len));
113
114        match stride {
115            syn::Expr::Lit(s) => {
116                if let syn::Lit::Int(i) = &s.lit {
117                    let stride_len = i.base10_digits().parse::<u8>().unwrap();
118                    strides_num.push(stride_len);
119                    strides_all_len_level.push(format_ident!("l{}", s_accu));
120
121                    match stride_len {
122                        3 => {
123                            strides_len3.push(s_accu as usize);
124                            strides_len3_l.push(format_ident!("l{}", s_accu));
125                        }
126                        4 => {
127                            strides_len4.push(s_accu as usize);
128                            strides_len4_l.push(format_ident!("l{}", s_accu));
129                        }
130                        5 => {
131                            strides_len5.push(s_accu as usize);
132                            strides_len5_l.push(format_ident!("l{}", s_accu));
133                        }
134                        _ => panic!("Expected a stride of 3, 4 or 5"),
135                    };
136                    strides_all_len_accu.push(s_accu);
137
138                    s_accu += stride_len;
139                    strides.push(format_ident!("Stride{}", stride_len))
140                } else {
141                    panic!("Expected an integer")
142                }
143            }
144            _ => {
145                panic!("Expected a literal")
146            }
147        }
148    }
149
150    // Check if the strides division makes sense
151    let mut len_to_stride_arr = [0_u8; 128];
152    strides_all_len_accu
153        .iter()
154        .zip(strides_num.iter())
155        .for_each(|(acc, s)| {
156            len_to_stride_arr[*acc as usize] = *s;
157        });
158
159    // These are the stride sizes as an array of u8s, padded with 0s to the
160    // right. It's bounded to 42 u8s to avoid having to set a const generic
161    // on the type (which would have to be carried over to its parent). So
162    // if a 0 is encountered, it's the end of the strides.
163    let mut stride_sizes = [0; 42];
164    let (left, _right) = stride_sizes.split_at_mut(strides_len as usize);
165    left.swap_with_slice(&mut strides_num);
166
167    let struct_creation = quote! {
168
169        #[derive(Debug)]
170        pub(crate) struct #buckets_name<AF: AddressFamily> {
171            // created fields for each sub-prefix (StrideNodeId) length,
172            // with hard-coded field-names, like this:
173            // l0: NodeSet<AF, Stride5>,
174            // l5: NodeSet<AF, Stride5>,
175            // l10: NodeSet<AF, Stride4>,
176            // ...
177            // l29: NodeSet<AF, Stride3>
178            # ( #strides_all_len_level: NodeSet<#ip_af, #strides>, )*
179            _af: PhantomData<AF>,
180            stride_sizes: [u8; 42],
181            strides_len: u8
182        }
183
184        #[derive(Debug)]
185        pub(crate) struct #prefixes_buckets_name<AF: AddressFamily, M: Meta> {
186            // creates a bucket for each prefix (PrefixId) length, with
187            // hard-coded field-names, like this:
188            // p0: PrefixSet<AF, M>,
189            // p1: PrefixSet<AF, M>,
190            // ...
191            // p32: PrefixSet<AF, M>,
192            #( #prefixes_all_len: PrefixSet<#ip_af, M>, )*
193            _af: PhantomData<AF>,
194            _m: PhantomData<M>,
195        }
196
197    };
198
199    let prefix_buckets_map = if ip_af.path.is_ident("IPv4") {
200        crate::maps::prefix_buckets_map_v4()
201    } else {
202        crate::maps::prefix_buckets_map_v6()
203    };
204
205    let prefix_buckets_impl = quote! {
206
207        impl<AF: AddressFamily, M: Meta> PrefixBuckets<#ip_af, M> for #prefixes_buckets_name<AF, M> {
208            fn init() -> #prefixes_buckets_name<AF, M> {
209                #prefixes_buckets_name {
210                    #( #prefixes_all_len: PrefixSet::init(1 << #prefixes_buckets_name::<AF, M>::get_bits_for_len(#all_len, 0)), )*
211                    _af: PhantomData,
212                    _m: PhantomData,
213                }
214            }
215
216            fn remove(&mut self, id: PrefixId<#ip_af>) -> Option<M> { unimplemented!() }
217
218            #get_root_prefix_set
219
220            #prefix_buckets_map
221
222        }
223
224    };
225
226    let struct_impl = quote! {
227
228        impl<AF: AddressFamily> NodeBuckets<#ip_af> for #buckets_name<AF> {
229            fn init() -> Self {
230                #buckets_name {
231                    // creates l0, l1, ... l<AF::BITS>, but only for the
232                    // levels at the end of each stride, so for strides
233                    // [5,5,4,3,3,3,3,3,3] is will create l0, l5, l10, l14,
234                    // l17, l20, l23, l26, l29 last level will be omitted,
235                    // because that will never be used (l29 has children
236                    // with prefixes up to prefix-length 32 in this example).
237                    #( #strides_all_len_level: NodeSet::init(#buckets_name::<AF>::len_to_store_bits(#strides_all_len_accu, 0) ), )*
238                    _af: PhantomData,
239                    stride_sizes: [ #( #stride_sizes, )*],
240                    strides_len: #strides_len
241                }
242            }
243
244            fn get_store3(&self, id: StrideNodeId<#ip_af>) -> &NodeSet<#ip_af, Stride3> {
245                match id.get_id().1 as usize {
246                    #( #strides_len3 => &self.#strides_len3_l, )*
247                    _ => panic!(
248                        "unexpected sub prefix length {} in stride size 3 ({})",
249                        id.get_id().1,
250                        id
251                    ),
252                }
253            }
254
255            fn get_store4(&self, id: StrideNodeId<#ip_af>) -> &NodeSet<#ip_af, Stride4> {
256                match id.get_id().1 as usize {
257                    #( #strides_len4 => &self.#strides_len4_l, )*
258                    // ex.:
259                    // 10 => &self.l10,
260                    _ => panic!(
261                        "unexpected sub prefix length {} in stride size 4 ({})",
262                        id.get_id().1,
263                        id
264                    ),
265                }
266            }
267
268            fn get_store5(&self, id: StrideNodeId<#ip_af>) -> &NodeSet<#ip_af, Stride5> {
269                match id.get_id().1 as usize {
270                    #( #strides_len5 => &self.#strides_len5_l, )*
271                    // ex.:
272                    // 0 => &self.l0,
273                    // 5 => &self.l5,
274                    _ => panic!(
275                        "unexpected sub prefix length {} in stride size 5 ({})",
276                        id.get_id().1,
277                        id
278                    ),
279                }
280            }
281
282            #[inline]
283            fn get_stride_sizes(&self) -> &[u8] {
284                &self.stride_sizes[0..self.strides_len as usize]
285            }
286
287            #[inline]
288            fn get_stride_for_id(&self, id: StrideNodeId<#ip_af>) -> u8 {
289                [ #(#len_to_stride_arr, )* ][id.get_id().1 as usize]
290            }
291
292            #[inline]
293            #store_bits
294
295            fn get_strides_len() -> u8 {
296                #strides_len
297            }
298
299            fn get_first_stride_size() -> u8 {
300                #first_stride_size
301            }
302        }
303
304    };
305
306    let type_alias = quote! {
307        type #type_name<M> = TreeBitMap<#ip_af, M, #buckets_name<#ip_af>, #prefixes_buckets_name<#ip_af, M>>;
308    };
309
310    let result = quote! {
311        #struct_creation
312        #struct_impl
313        #prefix_buckets_impl
314        #type_alias
315    };
316
317    TokenStream::from(result)
318}
319
320// ---------- Create Store struct -------------------------------------------
321
322// This macro creates the struct that will be the public API for the
323// PrefixStore. Therefore all methods defined in here should be public.
324
325/// Creates a new, user-named struct with user-defined specified stride sizes
326/// that can used as a store type.
327///
328/// # Usage
329/// ```ignore
330/// use rotonda_store::prelude::*;
331/// use rotonda_store::prelude::multi::*;
332/// use rotonda_store::meta_examples::PrefixAs;
333///
334/// const IP4_STRIDE_ARRAY = [4; 8];
335/// const IP6_STRIDE_ARRAY = [4; 32];
336///
337/// #[create_store((IPV4_STRIDE_ARRAY, IPV6_STRIDE_ARRAY))]
338/// struct NuStorage;
339/// ```
340///
341/// This will create a `NuStorage` struct, that can be used as a regular
342/// store.
343///
344/// The stride-sizes can be any of \[3,4,5\], and they should add up
345/// to the total number of bits in the address family (32 for IPv4 and
346/// 128 for IPv6). Stride sizes in the array will be repeated if the sum
347/// of them falls short of the total number of bits for the address
348/// family.
349///
350/// # Example
351/// ```ignore
352/// use rotonda_store::prelude::*;
353/// use rotonda_store::prelude::multi::*;
354/// use rotonda_store::meta_examples::PrefixAs;
355///
356/// // The default stride sizes for IPv4, IPv6, resp.
357/// #[create_store((
358///     [5, 5, 4, 3, 3, 3, 3, 3, 3, 3],
359///     [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
360///     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
361/// ))]
362/// struct NuStore;
363///
364/// let store = Arc::new(NuStore::<PrefixAs>::new().unwrap());
365/// ```
366#[proc_macro_attribute]
367pub fn create_store(attr: TokenStream, item: TokenStream) -> TokenStream {
368    let input = parse_macro_input!(item as syn::ItemStruct);
369    let store_name = &input.ident;
370
371    let attr = parse_macro_input!(attr as syn::ExprTuple);
372    let attrs = attr.elems.iter().collect::<Vec<_>>();
373    let strides4 = attrs[0].clone();
374    let strides6 = attrs[1].clone();
375    let strides4_name = format_ident!("{}IPv4", store_name);
376    let strides6_name = format_ident!("{}IPv6", store_name);
377
378    let create_strides = quote! {
379        use ::std::marker::PhantomData;
380        use ::inetnum::addr::Prefix;
381
382        #[stride_sizes((IPv4, #strides4))]
383        struct #strides4_name;
384
385        #[stride_sizes((IPv6, #strides6))]
386        struct #strides6_name;
387    };
388
389    let store = quote! {
390        /// A concurrently read/writable, lock-free Prefix Store, for use in a
391        /// multi-threaded context.
392        ///
393        /// This store will hold records keyed on Prefix, and with values
394        /// consisting of a multi-map (a map that can hold multiple values per
395        /// key), filled with Records.
396        ///
397        /// Records in the store contain the metadata, a `multi_uniq_id`,
398        /// logical time (to disambiguate the order of inserts into the store)
399        /// and the status of the Record.
400        ///
401        /// Effectively this means that the store holds values for the set of
402        /// `(prefix, multi_uniq_id)` pairs, where the primary key is the
403        /// prefix, and the secondary key is the `multi_uniq_id`. These
404        /// `multi_uniq_id`s are unique across all of the store. The store
405        /// facilitates iterating over and changing the status for all
406        /// prefixes per `multi_uniq_id`.
407        ///
408        /// The store has the concept of a global status for a
409        /// `multi_uniq_id`, e.g. to set all prefixes for a `multi_uniq_id` in
410        /// one atomic transaction to withdrawn. It also has local statuses
411        /// per `(prefix, multi_uniq_id)` pairs, e.g. to withdraw one value
412        /// for a `multi_uniq_id`.
413        ///
414        /// This way the store can hold RIBs for multiple peers in one
415        /// data-structure.
416        pub struct #store_name<
417            M: Meta
418        > {
419            v4: #strides4_name<M>,
420            v6: #strides6_name<M>,
421        }
422
423        impl<
424                M: Meta
425            > Default for #store_name<M>
426        {
427            fn default() -> Self {
428                Self::new().expect("failed to create store")
429            }
430        }
431
432        impl<
433                M: Meta
434            > #store_name<M>
435        {
436            /// Creates a new empty store with a tree for IPv4 and on for IPv6.
437            ///
438            /// The store will be created with the default stride sizes. After
439            /// creation you can wrap the store in an Arc<_> and `clone()` that
440            /// for every thread that needs read access and/or write acces to
441            /// it. As a convenience both read and write methods take a `&self`
442            /// instead of `&mut self`.
443            ///
444            /// If you need custom stride sizes you can use the
445            /// [`#[create_store]`](rotonda_macros::create_store) macro to
446            /// create a struct with custom stride sizes.
447            ///
448            /// # Example
449            /// ```
450            /// use std::{sync::Arc, thread};
451            /// use std::net::Ipv4Addr;
452            ///
453            /// use rotonda_store::prelude::*;
454            /// use rotonda_store::prelude::multi::*;
455            /// use rotonda_store::meta_examples::{NoMeta, PrefixAs};
456            ///
457            /// let tree_bitmap = Arc::new(MultiThreadedStore::<NoMeta>::new().unwrap());
458            ///
459            /// let _: Vec<_> = (0..16)
460            ///      .map(|_| {
461            ///         let tree_bitmap = tree_bitmap.clone();
462            ///
463            ///         thread::spawn(move || {
464            ///              let pfxs = [
465            ///                 Prefix::new_relaxed(
466            ///                     Ipv4Addr::new(130, 55, 241, 0).into(),
467            ///                     24,
468            ///                 ),
469            ///                 Prefix::new_relaxed(
470            ///                     Ipv4Addr::new(130, 55, 240, 0).into(),
471            ///                     24,
472            ///                 )
473            ///              ];
474            ///
475            ///              for pfx in pfxs.into_iter() {
476            ///                  println!("insert {}", pfx.unwrap());
477            ///                  tree_bitmap.insert(
478            ///                      &pfx.unwrap(),
479            ///                      Record::new(0, 0, RouteStatus::Active, NoMeta::Empty),
480            ///                      None
481            ///                  ).unwrap();
482            ///              }
483            ///          })
484            ///      }).map(|t| t.join()).collect();
485            /// ```
486            pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
487                Ok(Self {
488                    v4: #strides4_name::new()?,
489                    v6: #strides6_name::new()?,
490                })
491            }
492        }
493
494        impl<'a, M: Meta,
495            > #store_name<M>
496        {
497            /// Search for and return one or more prefixes that match the given
498            /// `search_pfx` argument.
499            ///
500            /// The search will return a [QueryResult] with the matching prefix,
501            /// if any, the type of match for the found prefix and the more and
502            /// less specifics for the requested prefix. The inclusion of more-
503            /// or less-specifics and the requested `match_type` is configurable
504            /// through the [MatchOptions] argument.
505            ///
506            /// The `match_type` in the `MatchOptions` indicates what match
507            /// types can appear in the [QueryResult] result.
508            ///
509            /// `ExactMatch` is the most strict, and will only allow exactly
510            /// matching prefixes in the result. Failing an exacly matching
511            /// prefix, it will return an `EmptyMatch`.
512            ///
513            /// `LongestMatch` is less strict, and either an exactly matching
514            /// prefix or - in case there is no exact match - a longest matching
515            /// prefix will be allowed in the result. Failing both an EmptyMatch
516            /// will be returned.
517            ///
518            /// For both `ExactMatch` and `LongestMatch` the
519            /// `include_less_specifics` and `include_more_specifics` options
520            /// will be respected and the result will contain the more and less
521            /// specifics according to the options for the requested prefix,
522            /// even if the result returns a `match_type` of `EmptyMatch`.
523            ///
524            /// `EmptyMatch` is the least strict, and will *always* return the
525            /// requested prefix, be it exactly matching, longest matching or not
526            /// matching at all (empty match), again, together with its less|more
527            /// specifics (if requested). Note that the last option, the empty
528            /// match in the result will never return less-specifics, but can
529            /// return more-specifics for a prefix that itself is not present
530            /// in the store.
531            ///
532            ///
533            /// This table sums it up:
534            ///
535            /// | query match_type | possible result types                      | less-specifics? | more-specifics? |
536            /// | ---------------- | ------------------------------------------ | --------------- | --------------- |
537            /// | `ExactMatch`     | `ExactMatch`, `EmptyMatch`                 | maybe           | maybe           |
538            /// | `LongestMatch`   | `ExactMatch`, `LongestMatch`, `EmptyMatch` | maybe           | maybe           |
539            /// | `EmptyMatch`     | `ExactMatch`, `LongestMatch`, `EmptyMatch` | no for EmptyM res, maybe for others | yes for EmptyM for res, maybe for others |
540            ///
541            ///
542            /// Note that the behavior of the CLI command `show route exact` on
543            /// most router platforms can be modeled by setting the `match_type`
544            /// to `ExactMatch` and `include_less_specifics` to `true`.
545            ///
546            /// # Example
547            /// ```
548            /// use std::net::Ipv4Addr;
549            ///
550            /// use rotonda_store::prelude::*;
551            /// use rotonda_store::meta_examples::PrefixAs;
552            /// use rotonda_store::prelude::multi::*;
553            ///
554            /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
555            /// let guard = &epoch::pin();
556            ///
557            /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
558            ///         .unwrap()
559            ///         .into();
560            ///
561            /// store.insert(
562            ///     &Prefix::new(pfx_addr, 22).unwrap(),
563            ///     Record::new(0, 0, RouteStatus::Active, PrefixAs(211321)),
564            ///     None
565            /// );
566            ///
567            /// let res = store.match_prefix(
568            ///     &Prefix::new(pfx_addr, 24).unwrap(),
569            ///     &MatchOptions {
570            ///         match_type: MatchType::LongestMatch,
571            ///         include_withdrawn: false,
572            ///         include_less_specifics: false,
573            ///         include_more_specifics: false,
574            ///         mui: None
575            ///     },
576            ///     guard
577            /// );
578            ///
579            /// assert_eq!(res.prefix_meta[0].meta.0, 211321);
580            ///
581            /// let res = store.match_prefix(
582            ///     &Prefix::new(pfx_addr, 24).unwrap(),
583            ///         &MatchOptions {
584            ///             match_type: MatchType::ExactMatch,
585            ///             include_withdrawn: false,
586            ///             include_less_specifics: false,
587            ///             include_more_specifics: false,
588            ///             mui: None
589            ///         },
590            ///         guard
591            ///     );
592            ///
593            /// assert!(res.match_type.is_empty());
594            ///
595            /// ```
596            pub fn match_prefix(
597                &'a self,
598                search_pfx: &Prefix,
599                options: &MatchOptions,
600                guard: &'a Guard,
601            ) -> QueryResult<M> {
602
603                match search_pfx.addr() {
604                    std::net::IpAddr::V4(addr) => {
605                        self.v4.match_prefix_by_store_direct(
606                            PrefixId::<IPv4>::new(
607                                addr.into(),
608                                search_pfx.len(),
609                            ),
610                            options,
611                            options.mui,
612                            guard
613                        )
614                    },
615                    std::net::IpAddr::V6(addr) => self.v6.match_prefix_by_store_direct(
616                        PrefixId::<IPv6>::new(
617                            addr.into(),
618                            search_pfx.len(),
619                        ),
620                        options,
621                        options.mui,
622                        guard
623                    ),
624                }
625            }
626
627            /// Return the record that belongs to the pre-calculated and
628            /// stored best path for a given prefix.
629            ///
630            /// If the Prefix does not exist in the store `None` is returned.
631            /// If the prefix does exist, but no best path was calculated
632            /// (yet), a `PrefixStoreError::BestPathNotFound` error will be
633            /// returned. A returned result of
634            /// `PrefixError::StoreNotReadyError` should never happen: it
635            /// would indicate an internal inconsistency in the store.
636            pub fn best_path(&'a self,
637                search_pfx: &Prefix,
638                guard: &Guard
639            ) -> Option<Result<Record<M>, PrefixStoreError>> {
640
641                match search_pfx.addr() {
642                    std::net::IpAddr::V4(addr) => self.v4.store
643                        .non_recursive_retrieve_prefix(
644                            PrefixId::<IPv4>::new(
645                                addr.into(),
646                                search_pfx.len(),
647                            ),
648                        )
649                        .0
650                        .map(|p_rec| unsafe { p_rec
651                            .get_path_selections(guard).best()
652                            .map_or_else(
653                                || Err(PrefixStoreError::BestPathNotFound),
654                                |mui| p_rec.record_map
655                                    .get_record_for_active_mui(mui)
656                                    .ok_or(PrefixStoreError::StoreNotReadyError)
657                            )
658                        }),
659                    std::net::IpAddr::V6(addr) => self.v6.store
660                        .non_recursive_retrieve_prefix(
661                            PrefixId::<IPv6>::new(
662                                addr.into(),
663                                search_pfx.len(),
664                            ),
665                        )
666                        .0
667                        .map(|p_rec| unsafe { p_rec
668                            .get_path_selections(guard).best()
669                            .map_or_else(
670                                || Err(PrefixStoreError::BestPathNotFound),
671                                |mui| p_rec.record_map
672                                    .get_record_for_active_mui(mui)
673                                    .ok_or(PrefixStoreError::StoreNotReadyError)
674                            )
675                        })
676                }
677            }
678
679            /// Calculate and store the best path for the specified Prefix.
680            ///
681            /// If the result of the calculation is successful it will be
682            /// stored for the prefix. If they were set, it will return the
683            /// multi_uniq_id of the best path and the one for the backup
684            /// path, respectively. If the prefix does not exist in the store,
685            /// `None` will be returned. If the best path cannot be
686            /// calculated, a `Ok(None, None)` will be returned.
687            ///
688            /// Failing to calculate a best path, may be caused by
689            /// unavailability of any active paths, or by a lack of data (in
690            /// either the paths, or the supplied `TiebreakerInfo`).
691            ///
692            /// An Error result indicates an inconsistency in the store.
693            pub fn calculate_and_store_best_and_backup_path(
694                &self,
695                search_pfx: &Prefix,
696                tbi: &<M as Meta>::TBI,
697                guard: &Guard
698            ) -> Result<(Option<u32>, Option<u32>), PrefixStoreError> {
699                match search_pfx.addr() {
700                    std::net::IpAddr::V4(addr) => self.v4.store
701                        .non_recursive_retrieve_prefix(
702                            PrefixId::<IPv4>::new(
703                                addr.into(),
704                                search_pfx.len(),
705                            ),
706                            // guard
707                        ).0.map_or(
708                            Err(PrefixStoreError::StoreNotReadyError),
709                            |p_rec| p_rec.calculate_and_store_best_backup(
710                                tbi, guard),
711                        ),
712                    std::net::IpAddr::V6(addr) => self.v6.store
713                        .non_recursive_retrieve_prefix(
714                            PrefixId::<IPv6>::new(
715                                addr.into(),
716                                search_pfx.len(),
717                            ),
718                            // guard
719                        ).0.map_or(
720                            Err(PrefixStoreError::StoreNotReadyError),
721                            |p_rec| p_rec.calculate_and_store_best_backup(
722                                tbi, guard),
723                        ),
724                }
725            }
726
727            pub fn is_ps_outdated(
728                &self,
729                search_pfx: &Prefix,
730                guard: &Guard
731            ) -> Result<bool, PrefixStoreError> {
732                match search_pfx.addr() {
733                    std::net::IpAddr::V4(addr) => self.v4.store
734                        .non_recursive_retrieve_prefix(
735                            PrefixId::<IPv4>::new(
736                                addr.into(),
737                                search_pfx.len(),
738                            ),
739                            // guard
740                        ).0.map_or(
741                            Err(PrefixStoreError::StoreNotReadyError),
742                            |p| Ok(p.is_ps_outdated(guard))
743                        ),
744                    std::net::IpAddr::V6(addr) => self.v6.store
745                        .non_recursive_retrieve_prefix(
746                            PrefixId::<IPv6>::new(
747                                addr.into(),
748                                search_pfx.len(),
749                            ),
750                            // guard
751                        ).0.map_or(
752                            Err(PrefixStoreError::StoreNotReadyError),
753                            |p| Ok(p.is_ps_outdated(guard))
754                        )
755                }
756            }
757
758            /// Return a [QueryResult] that contains all the more-specific
759            /// prefixes of the `search_pfx` in the store, including the
760            /// meta-data of these prefixes.
761            ///
762            /// The `search_pfx` argument can be either a IPv4 or an IPv6
763            /// prefix. The `search_pfx` itself doesn't have to be present
764            /// in the store for an iterator to be non-empty, i.e. if
765            /// more-specific prefixes exist for a non-existent
766            /// `search_pfx` the iterator will yield these more-specific
767            /// prefixes.
768            ///
769            /// The `guard` should be a `&epoch::pin()`. It allows the
770            /// QuerySet to contain references to the meta-data objects,
771            /// instead of cloning them into it.
772            pub fn more_specifics_from(&'a self,
773                search_pfx: &Prefix,
774                mui: Option<u32>,
775                include_withdrawn: bool,
776                guard: &'a Guard,
777            ) -> QueryResult<M> {
778
779                match search_pfx.addr() {
780                    std::net::IpAddr::V4(addr) => self.v4.more_specifics_from(
781                        PrefixId::<IPv4>::new(
782                            addr.into(),
783                            search_pfx.len(),
784                        ),
785                        mui,
786                        include_withdrawn,
787                        guard
788                    ),
789                    std::net::IpAddr::V6(addr) => self.v6.more_specifics_from(
790                        PrefixId::<IPv6>::new(
791                            addr.into(),
792                            search_pfx.len(),
793                        ),
794                        mui,
795                        include_withdrawn,
796                        guard
797                    ),
798                }
799            }
800
801            /// Return a `QuerySet` that contains all the less-specific
802            /// prefixes of the `search_pfx` in the store, including the
803            /// meta-data of these prefixes.
804            ///
805            /// The `search_pfx` argument can be either a IPv4 or an IPv6
806            /// prefix. The `search_pfx` itself doesn't have to be present
807            /// in the store for an iterator to be non-empty, i.e. if
808            /// less-specific prefixes exist for a non-existent
809            /// `search_pfx` the iterator will yield these less-specific
810            /// prefixes.
811            ///
812            /// The `guard` should be a `&epoch::pin()`. It allows the
813            /// QuerySet to contain references to the meta-data objects,
814            /// instead of cloning them into it.
815            pub fn less_specifics_from(&'a self,
816                search_pfx: &Prefix,
817                mui: Option<u32>,
818                include_withdrawn: bool,
819                guard: &'a Guard,
820            ) -> QueryResult<M> {
821
822                match search_pfx.addr() {
823                    std::net::IpAddr::V4(addr) => self.v4.less_specifics_from(
824                        PrefixId::<IPv4>::new(
825                            addr.into(),
826                            search_pfx.len(),
827                        ),
828                        mui,
829                        include_withdrawn,
830                        guard
831                    ),
832                    std::net::IpAddr::V6(addr) => self.v6.less_specifics_from(
833                        PrefixId::<IPv6>::new(
834                            addr.into(),
835                            search_pfx.len(),
836                        ),
837                        mui,
838                        include_withdrawn,
839                        guard
840                    ),
841                }
842            }
843
844            /// Returns an iterator over all the less-specific prefixes
845            /// of the `search_prefix`, if present in the store, including
846            /// the meta-data of these prefixes.
847            ///
848            /// The `search_pfx` argument can be either a IPv4 or an IPv6
849            /// prefix. The `search_pfx` itself doesn't have to be present
850            /// in the store for an iterator to be non-empty, i.e. if
851            /// less-specific prefixes exist for a non-existent
852            /// `search_pfx` the iterator will yield these less-specific
853            /// prefixes.
854            ///
855            /// The `guard` should be a `&epoch::pin()`. It allows the
856            /// iterator to create and return references to the meta-data
857            /// objects to the caller (instead of cloning them).
858            ///
859            /// # Example
860            /// ```
861            /// use std::net::Ipv4Addr;
862            ///
863            /// use rotonda_store::prelude::*;
864            /// use rotonda_store::meta_examples::PrefixAs;
865            /// use rotonda_store::prelude::multi::*;
866            ///
867            ///
868            /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
869            /// let guard = epoch::pin();
870            ///
871            /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
872            ///         .unwrap()
873            ///         .into();
874            ///
875            /// store.insert(
876            ///     &Prefix::new(pfx_addr, 22).unwrap(),
877            ///     Record::new(0, 0, RouteStatus::Active, PrefixAs(211321)),
878            ///     None
879            /// );
880            ///
881            /// for prefix_record in store.less_specifics_iter_from(
882            ///     &Prefix::new(pfx_addr, 24).unwrap(),
883            ///     None,
884            ///     false,
885            ///     &guard
886            /// ) {
887            ///    assert_eq!(prefix_record.meta[0].meta.0, 211321);
888            /// }
889            /// ```
890            pub fn less_specifics_iter_from(&'a self,
891                search_pfx: &Prefix,
892                mui: Option<u32>,
893                include_withdrawn: bool,
894                guard: &'a Guard,
895                ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
896                    let (left, right) = match search_pfx.addr() {
897                        std::net::IpAddr::V4(addr) => {
898                            (
899                                Some(self.v4.store.less_specific_prefix_iter(
900                                        PrefixId::<IPv4>::new(
901                                            addr.into(),
902                                            search_pfx.len(),
903                                        ),
904                                        mui,
905                                        include_withdrawn,
906                                        guard
907                                    )
908                                    .map(|p| PrefixRecord::from(p))
909                                ),
910                                None
911                            )
912                        }
913                        std::net::IpAddr::V6(addr) => {
914                            (
915                                None,
916                                Some(self.v6.store.less_specific_prefix_iter(
917                                        PrefixId::<IPv6>::new(
918                                            addr.into(),
919                                            search_pfx.len(),
920                                        ),
921                                        mui,
922                                        include_withdrawn,
923                                        guard
924                                    )
925                                    .map(|p| PrefixRecord::from(p))
926                                )
927                            )
928                        }
929                    };
930                    left.into_iter().flatten().chain(right.into_iter().flatten())
931                }
932
933            /// Returns an iterator over all the more-specifics prefixes
934            /// of the `search_prefix`, if present in the store, including
935            /// the meta-data of these prefixes.
936            ///
937            /// The `search_pfx` argument can be either a IPv4 or an IPv6
938            /// prefix. The `search_pfx` itself doesn't have to be present
939            /// in the store for an iterator to be non-empty, i.e. if
940            /// more-specific prefixes exist for a non-existent
941            /// `search_pfx` the iterator will yield these more-specific
942            /// prefixes.
943            ///
944            /// The `guard` should be a `&epoch::pin()`. It allows the
945            /// iterator to create and return references to the meta-data
946            /// objects to the caller (instead of cloning them).
947            ///
948            /// # Example
949            /// ```
950            /// use std::net::Ipv4Addr;
951            ///
952            /// use rotonda_store::prelude::*;
953            /// use rotonda_store::prelude::multi::*;
954            /// use rotonda_store::meta_examples::PrefixAs;
955            ///
956            /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
957            /// let guard = epoch::pin();
958            ///
959            /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
960            ///         .unwrap()
961            ///         .into();
962            ///
963            /// store.insert(
964            ///     &Prefix::new(pfx_addr, 24).unwrap(),
965            ///     Record::new(0, 0, RouteStatus::Active, PrefixAs(211321)),
966            ///     None
967            /// );
968            ///
969            /// for prefix_record in store.more_specifics_iter_from(
970            ///     &Prefix::new(pfx_addr, 22).unwrap(),
971            ///     None,
972            ///     false,
973            ///     &guard
974            /// ) {
975            ///    assert_eq!(prefix_record.meta[0].meta.0, 211321);
976            /// }
977            /// ```
978            pub fn more_specifics_iter_from(&'a self,
979                search_pfx: &Prefix,
980                mui: Option<u32>,
981                include_withdrawn: bool,
982                guard: &'a Guard,
983            ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
984
985                let (left, right) = match search_pfx.addr() {
986                    std::net::IpAddr::V4(addr) => {
987                        let bmin = unsafe {
988                            self.v4.store.withdrawn_muis_bmin.load(
989                                Ordering::Acquire, guard
990                            ).deref()
991                        };
992                        if mui.is_some() && bmin.contains(mui.unwrap()) {
993                                (None, None)
994                            } else {
995                                (
996                                    Some(self.v4.store.more_specific_prefix_iter_from(
997                                            PrefixId::<IPv4>::new(
998                                                addr.into(),
999                                                search_pfx.len(),
1000                                            ),
1001                                            mui,
1002                                            include_withdrawn,
1003                                            guard
1004                                        ).map(|p| PrefixRecord::from(p))
1005                                    ),
1006                                    None
1007                                )
1008                            }
1009                        }
1010                    std::net::IpAddr::V6(addr) => {
1011                        let bmin = unsafe {
1012                            self.v6.store.withdrawn_muis_bmin.load(
1013                                Ordering::Acquire, guard
1014                            ).deref()
1015                        };
1016                        if mui.is_some() && bmin.contains(mui.unwrap()) {
1017                            (None, None)
1018                        } else {
1019                            (
1020                                None,
1021                                Some(self.v6.store.more_specific_prefix_iter_from(
1022                                        PrefixId::<IPv6>::new(
1023                                            addr.into(),
1024                                            search_pfx.len(),
1025                                        ),
1026                                        mui,
1027                                        include_withdrawn,
1028                                        guard
1029                                    ).map(|p| PrefixRecord::from(p))
1030                                )
1031                            )
1032                        }
1033                    }
1034                };
1035                left.into_iter().flatten().chain(right.into_iter().flatten())
1036            }
1037
1038            pub fn iter_records_for_mui_v4(
1039                &'a self,
1040                mui: u32,
1041                include_withdrawn: bool,
1042                guard: &'a Guard
1043            ) -> impl Iterator<Item=PrefixRecord<M>> +'a {
1044
1045                let bmin = unsafe {
1046                    self.v4.store.withdrawn_muis_bmin.load(
1047                        Ordering::Acquire, guard
1048                    ).deref()
1049                };
1050
1051                if bmin.contains(mui) && !include_withdrawn {
1052                    None
1053                } else {
1054                    Some(
1055                        self.v4.store.more_specific_prefix_iter_from(
1056                                PrefixId::<IPv4>::new(
1057                                    0,
1058                                    0,
1059                                ),
1060                                Some(mui),
1061                                include_withdrawn,
1062                                guard
1063                            ).map(|p| PrefixRecord::from(p))
1064                    )
1065                }.into_iter().flatten()
1066            }
1067
1068            pub fn iter_records_for_mui_v6(
1069                &'a self,
1070                mui: u32,
1071                include_withdrawn: bool,
1072                guard: &'a Guard
1073            ) -> impl Iterator<Item=PrefixRecord<M>> +'a {
1074
1075                let bmin = unsafe {
1076                    self.v4.store.withdrawn_muis_bmin.load(
1077                        Ordering::Acquire, guard
1078                    ).deref()
1079                };
1080
1081                if bmin.contains(mui) && !include_withdrawn {
1082                    None
1083                } else {
1084                    Some(
1085                        self.v6.store.more_specific_prefix_iter_from(
1086                                PrefixId::<IPv6>::new(
1087                                    0,
1088                                    0,
1089                                ),
1090                                Some(mui),
1091                                include_withdrawn,
1092                                guard
1093                            ).map(|p| PrefixRecord::from(p))
1094                    )
1095                }.into_iter().flatten()
1096            }
1097
1098            /// Insert or replace a Record into the Store
1099            ///
1100            /// The specified Record will replace an existing record in the
1101            /// store if the multi-map for the specified prefix already has an
1102            /// entry for the `multi_uniq_id`, otherwise it will be added to
1103            /// the multi-map.
1104            ///
1105            /// If the `update_path_sections` argument is used the best path
1106            /// selection will be run on the resulting multi-map after insert
1107            /// and stored for the specified prefix.
1108            ///
1109            /// Returns some metrics about the resulting insert.
1110            pub fn insert(
1111                &self,
1112                prefix: &Prefix,
1113                record: Record<M>,
1114                update_path_selections: Option<M::TBI>
1115            ) -> Result<UpsertReport, PrefixStoreError> {
1116                match prefix.addr() {
1117                    std::net::IpAddr::V4(addr) => {
1118                        self.v4.insert(
1119                            PrefixId::<IPv4>::from(*prefix),
1120                            record,
1121                            update_path_selections,
1122                        )
1123                    }
1124                    std::net::IpAddr::V6(addr) => {
1125                        self.v6.insert(
1126                            PrefixId::<IPv6>::from(*prefix),
1127                            record,
1128                            update_path_selections,
1129                        )
1130                    }
1131                }
1132            }
1133
1134            /// Returns an unordered iterator over all prefixes, with any
1135            /// status (including Withdrawn), for both IPv4 and IPv6,
1136            /// currently in the store, including meta-data.
1137            ///
1138            /// Although the iterator is unordered within an address-family,
1139            /// it first iterates over all IPv4 addresses and then over all
1140            /// IPv6 addresses.
1141            ///
1142            /// The `guard` should be a `&epoch::pin()`. It allows the
1143            /// iterator to create and return references to the meta-data
1144            /// objects to the caller (instead of cloning them).
1145            ///
1146            /// # Example
1147            /// ```
1148            /// use std::net::Ipv4Addr;
1149            ///
1150            /// use rotonda_store::prelude::*;
1151            /// use rotonda_store::prelude::multi::*;
1152            /// use rotonda_store::meta_examples::PrefixAs;
1153            ///
1154            /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
1155            /// let guard = epoch::pin();
1156            ///
1157            /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
1158            ///         .unwrap()
1159            ///         .into();
1160            /// let our_asn = Record::new(0, 0, RouteStatus::Active, PrefixAs(211321));
1161            ///
1162            /// store.insert(&Prefix::new(pfx_addr, 22).unwrap(), our_asn.clone(), None);
1163            /// store.insert(&Prefix::new(pfx_addr, 23).unwrap(), our_asn.clone(), None);
1164            /// store.insert(&Prefix::new(pfx_addr, 24).unwrap(), our_asn.clone(), None);
1165            /// store.insert(&Prefix::new(pfx_addr, 25).unwrap(), our_asn, None);
1166            ///
1167            /// let mut iter = store.prefixes_iter();
1168            ///
1169            /// assert_eq!(iter.next().unwrap().prefix,
1170            ///     Prefix::new(pfx_addr, 22).unwrap());
1171            /// assert_eq!(iter.next().unwrap().prefix,
1172            ///     Prefix::new(pfx_addr, 23).unwrap());
1173            /// assert_eq!(iter.next().unwrap().prefix,
1174            ///     Prefix::new(pfx_addr, 24).unwrap());
1175            /// assert_eq!(iter.next().unwrap().prefix,
1176            ///     Prefix::new(pfx_addr, 25).unwrap());
1177            /// ```
1178            pub fn prefixes_iter(
1179                &'a self,
1180            ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
1181                self.v4.store.prefixes_iter()
1182                    .map(|p| PrefixRecord::from(p))
1183                    .chain(
1184                        self.v6.store.prefixes_iter()
1185                        .map(|p| PrefixRecord::from(p))
1186                    )
1187            }
1188
1189            /// Returns an unordered iterator over all IPv4 prefixes in the
1190            /// currently in the store, with any status (including Withdrawn),
1191            /// including meta-data.
1192            ///
1193            /// The `guard` should be a `&epoch::pin()`. It allows the
1194            /// iterator to create and return references to the meta-data
1195            /// objects to the caller (instead of cloning them).
1196            ///
1197            /// # Example
1198            /// ```
1199            /// use std::net::Ipv4Addr;
1200            ///
1201            /// use rotonda_store::prelude::*;
1202            /// use rotonda_store::prelude::multi::*;
1203            /// use rotonda_store::meta_examples::PrefixAs;
1204            ///
1205            /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
1206            /// let guard = epoch::pin();
1207            ///
1208            /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
1209            ///         .unwrap()
1210            ///         .into();
1211            /// let our_asn = Record::new(0, 0, RouteStatus::Active, PrefixAs(211321));
1212            ///
1213            /// store.insert(&Prefix::new(pfx_addr, 22).unwrap(), our_asn.clone(), None);
1214            /// store.insert(&Prefix::new(pfx_addr, 23).unwrap(), our_asn.clone(), None);
1215            /// store.insert(&Prefix::new(pfx_addr, 24).unwrap(), our_asn.clone(), None);
1216            /// store.insert(&Prefix::new(pfx_addr, 25).unwrap(), our_asn, None);
1217            ///
1218            /// let mut iter = store.prefixes_iter();
1219            ///
1220            /// assert_eq!(iter.next().unwrap().prefix,
1221            ///     Prefix::new(pfx_addr, 22).unwrap());
1222            /// assert_eq!(iter.next().unwrap().prefix,
1223            ///     Prefix::new(pfx_addr, 23).unwrap());
1224            /// assert_eq!(iter.next().unwrap().prefix,
1225            ///     Prefix::new(pfx_addr, 24).unwrap());
1226            /// assert_eq!(iter.next().unwrap().prefix,
1227            ///     Prefix::new(pfx_addr, 25).unwrap());
1228            /// ```
1229            pub fn prefixes_iter_v4(
1230                &'a self,
1231            ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
1232                self.v4.store.prefixes_iter()
1233                    .map(|p| PrefixRecord::from(p))
1234            }
1235
1236            /// Returns an unordered iterator over all IPv6 prefixes in the
1237            /// currently in the store, with any status (including Withdrawn),
1238            /// including meta-data.
1239            ///
1240            /// The `guard` should be a `&epoch::pin()`. It allows the
1241            /// iterator to create and return references to the meta-data
1242            /// objects to the caller (instead of cloning them).
1243            ///
1244            /// # Example
1245            /// ```
1246            /// use std::net::Ipv6Addr;
1247            ///
1248            /// use rotonda_store::prelude::*;
1249            /// use rotonda_store::prelude::multi::*;
1250            /// use rotonda_store::meta_examples::PrefixAs;
1251            ///
1252            /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
1253            /// let guard = epoch::pin();
1254            ///
1255            /// let pfx_addr = "2a04:b900::".parse::<Ipv6Addr>()
1256            ///         .unwrap()
1257            ///         .into();
1258            /// let our_asn = Record::new(0, 0, RouteStatus::Active, PrefixAs(211321));
1259            ///
1260            /// store.insert(&Prefix::new(pfx_addr, 29).unwrap(), our_asn.clone(), None);
1261            /// store.insert(&Prefix::new(pfx_addr, 48).unwrap(), our_asn.clone(), None);
1262            /// store.insert(&Prefix::new(pfx_addr, 56).unwrap(), our_asn.clone(), None);
1263            /// store.insert(&Prefix::new(pfx_addr, 64).unwrap(), our_asn, None);
1264            ///
1265            /// let mut iter = store.prefixes_iter();
1266            ///
1267            /// assert_eq!(iter.next().unwrap().prefix,
1268            ///     Prefix::new(pfx_addr, 29).unwrap());
1269            /// assert_eq!(iter.next().unwrap().prefix,
1270            ///     Prefix::new(pfx_addr, 48).unwrap());
1271            /// assert_eq!(iter.next().unwrap().prefix,
1272            ///     Prefix::new(pfx_addr, 56).unwrap());
1273            /// assert_eq!(iter.next().unwrap().prefix,
1274            ///     Prefix::new(pfx_addr, 64).unwrap());
1275            /// ```
1276            pub fn prefixes_iter_v6(
1277                &'a self,
1278            ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
1279                self.v6.store.prefixes_iter()
1280                    .map(|p| PrefixRecord::from(p))
1281            }
1282
1283            /// Change the local status of the record for the combination of
1284            /// (prefix, multi_uniq_id) to Withdrawn. Note that by default the
1285            /// global `Withdrawn` status for a mui overrides the local status
1286            /// of a record.
1287            pub fn mark_mui_as_withdrawn_for_prefix(
1288                &self,
1289                prefix: &Prefix,
1290                mui: u32
1291            ) -> Result<(), PrefixStoreError> {
1292                let guard = &epoch::pin();
1293                match prefix.addr() {
1294                    std::net::IpAddr::V4(addr) => {
1295                        self.v4.store.mark_mui_as_withdrawn_for_prefix(
1296                            PrefixId::<IPv4>::from(*prefix),
1297                            mui,
1298                            // &guard
1299                        )
1300                    }
1301                    std::net::IpAddr::V6(addr) => {
1302                        self.v6.store.mark_mui_as_withdrawn_for_prefix(
1303                            PrefixId::<IPv6>::from(*prefix),
1304                            mui,
1305                            // &guard
1306                        )
1307                    }
1308                }
1309            }
1310
1311            /// Change the local status of the record for the combination of
1312            /// (prefix, multi_uniq_id) to Active. Note that by default the
1313            /// global `Withdrawn` status for a mui overrides the local status
1314            /// of a record.
1315            pub fn mark_mui_as_active_for_prefix(
1316                &self,
1317                prefix: &Prefix,
1318                mui: u32
1319            ) -> Result<(), PrefixStoreError> {
1320                let guard = &epoch::pin();
1321                match prefix.addr() {
1322                    std::net::IpAddr::V4(addr) => {
1323                        self.v4.store.mark_mui_as_active_for_prefix(
1324                            PrefixId::<IPv4>::from(*prefix),
1325                            mui,
1326                            // &guard
1327                        )
1328                    }
1329                    std::net::IpAddr::V6(addr) => {
1330                        self.v6.store.mark_mui_as_active_for_prefix(
1331                            PrefixId::<IPv6>::from(*prefix),
1332                            mui,
1333                            // &guard
1334                        )
1335                    }
1336                }
1337            }
1338
1339            /// Change the status of all records for IPv4 prefixes for this
1340            /// `multi_uniq_id` globally to Active.  Note that the global
1341            /// `Active` status will be overridden by the local status of the
1342            /// record.
1343            pub fn mark_mui_as_active_v4(
1344                &self,
1345                mui: u32
1346            ) -> Result<(), PrefixStoreError> {
1347                let guard = &epoch::pin();
1348
1349                self.v4.store.mark_mui_as_active(
1350                    mui,
1351                    &guard
1352                )
1353            }
1354
1355            /// Change the status of all records for IPv4 prefixes for this
1356            /// `multi_uniq_id` globally to Withdrawn. A global `Withdrawn`
1357            /// status for a `multi_uniq_id` overrides the local status of
1358            /// prefixes for this mui. However the local status can still be
1359            /// modified. This modification will take effect if the global
1360            /// status is changed to `Active`.
1361            pub fn mark_mui_as_withdrawn_v4(
1362                &self,
1363                mui: u32
1364            ) -> Result<(), PrefixStoreError> {
1365                let guard = &epoch::pin();
1366
1367                self.v4.store.mark_mui_as_withdrawn(
1368                    mui,
1369                    &guard
1370                )
1371            }
1372
1373            /// Change the status of all records for IPv6 prefixes for this
1374            /// `multi_uniq_id` globally to Active.  Note that the global
1375            /// `Active` status will be overridden by the local status of the
1376            /// record.
1377            pub fn mark_mui_as_active_v6(
1378                &self,
1379                mui: u32
1380            ) -> Result<(), PrefixStoreError> {
1381                let guard = &epoch::pin();
1382
1383                self.v6.store.mark_mui_as_active(
1384                    mui,
1385                    &guard
1386                )
1387            }
1388
1389            /// Change the status of all records for IPv6 prefixes for this
1390            /// `multi_uniq_id` globally to Withdrawn. A global `Withdrawn`
1391            /// status for a `multi_uniq_id` overrides the local status of
1392            /// prefixes for this mui. However the local status can still be
1393            /// modified. This modification will take effect if the global
1394            /// status is changed to `Active`.
1395            pub fn mark_mui_as_withdrawn_v6(
1396                &self,
1397                mui: u32
1398            ) -> Result<(), PrefixStoreError> {
1399                let guard = &epoch::pin();
1400
1401                self.v6.store.mark_mui_as_withdrawn(
1402                    mui,
1403                    &guard
1404                )
1405            }
1406
1407
1408            /// Change the status of all records for this `multi_uniq_id` to
1409            /// Withdrawn.
1410            ///
1411            /// This method tries to mark all records: first the IPv4 records,
1412            /// then the IPv6 records. If marking of the IPv4 records fails,
1413            /// the method continues and tries to mark the IPv6 records. If
1414            /// either or both fail, an error is returned.
1415            pub fn mark_mui_as_withdrawn(
1416                &self,
1417                mui: u32
1418            ) -> Result<(), PrefixStoreError> {
1419                let guard = &epoch::pin();
1420
1421                let res_v4 = self.v4.store.mark_mui_as_withdrawn(
1422                    mui,
1423                    &guard
1424                );
1425                let res_v6 = self.v6.store.mark_mui_as_withdrawn(
1426                    mui,
1427                    &guard
1428                );
1429
1430                res_v4.and(res_v6)
1431            }
1432
1433
1434
1435            // Whether the global status for IPv4 prefixes and the specified
1436            // `multi_uniq_id` is set to `Withdrawn`.
1437            pub fn mui_is_withdrawn_v4(
1438                &self,
1439                mui: u32
1440            ) -> bool {
1441                let guard = &epoch::pin();
1442
1443                self.v4.store.mui_is_withdrawn(mui, guard)
1444            }
1445
1446            // Whether the global status for IPv6 prefixes and the specified
1447            // `multi_uniq_id` is set to `Active`.
1448            pub fn mui_is_withdrawn_v6(
1449                &self,
1450                mui: u32
1451            ) -> bool {
1452                let guard = &epoch::pin();
1453
1454                self.v6.store.mui_is_withdrawn(mui, guard)
1455            }
1456
1457            /// Returns the number of all prefixes in the store.
1458            ///
1459            /// Note that this method will actually traverse the complete
1460            /// tree.
1461            pub fn prefixes_count(&self) -> usize {
1462                self.v4.store.get_prefixes_count()
1463                + self.v6.store.get_prefixes_count()
1464            }
1465
1466            /// Returns the number of all IPv4 prefixes in the store.
1467            ///
1468            /// Note that this counter may be lower than the actual
1469            /// number in the store, due to contention at the time of
1470            /// reading the value.
1471            pub fn prefixes_v4_count(&self) -> usize {
1472                self.v4.store.get_prefixes_count()
1473            }
1474
1475            /// Returns the number of all IPv4 prefixes with the
1476            /// supplied prefix length in the store.
1477            ///
1478            /// Note that this counter may be lower than the actual
1479            /// number in the store, due to contention at the time of
1480            /// reading the value.
1481            pub fn prefixes_v4_count_for_len(&self, len: u8) -> usize {
1482                self.v4.store.get_prefixes_count_for_len(len)
1483            }
1484
1485            /// Returns the number of all IPv6 prefixes in the store.
1486            ///
1487            /// Note that this counter may be lower than the actual
1488            /// number in the store, due to contention at the time of
1489            /// reading the value.
1490            pub fn prefixes_v6_count(&self) -> usize {
1491                self.v6.store.get_prefixes_count()
1492            }
1493
1494            /// Returns the number of all IPv6 prefixes with the
1495            /// supplied prefix length in the store.
1496            ///
1497            /// Note that this counter may be lower than the actual
1498            /// number in the store, due to contention at the time of
1499            /// reading the value.
1500            pub fn prefixes_v6_count_for_len(&self, len: u8) -> usize {
1501                self.v6.store.get_prefixes_count_for_len(len)
1502            }
1503
1504            /// Returns the number of nodes in the store.
1505            ///
1506            /// Note that this counter may be lower than the actual
1507            /// number in the store, due to contention at the time of
1508            /// reading the value.
1509            pub fn nodes_count(&self) -> usize {
1510                self.v4.store.get_nodes_count()
1511                + self.v6.store.get_nodes_count()
1512            }
1513
1514            /// Returns the number of IPv4 nodes in the store.
1515            ///
1516            /// Note that this counter may be lower than the actual
1517            /// number in the store, due to contention at the time of
1518            /// reading the value.
1519            pub fn nodes_v4_count(&self) -> usize {
1520                self.v4.store.get_nodes_count()
1521            }
1522
1523            /// Returns the number of IPv6 nodes in the store.
1524            ///
1525            /// Note that this counter may be lower than the actual
1526            /// number in the store, due to contention at the time of
1527            /// reading the value.
1528            pub fn nodes_v6_count(&self) -> usize {
1529                self.v6.store.get_nodes_count()
1530            }
1531
1532            /// Print the store statistics to the standard output.
1533            #[cfg(feature = "cli")]
1534            pub fn print_funky_stats(&self) {
1535                println!("");
1536                println!("Stats for IPv4 multi-threaded store\n");
1537                println!("{}", self.v4);
1538                println!("Stats for IPv6 multi-threaded store\n");
1539                println!("{}", self.v6);
1540            }
1541
1542            // The Store statistics.
1543            pub fn stats(&self) -> StoreStats {
1544                StoreStats {
1545                    v4: self.v4.store.counters.get_prefix_stats(),
1546                    v6: self.v6.store.counters.get_prefix_stats(),
1547                }
1548            }
1549        }
1550    };
1551
1552    let result = quote! {
1553        #create_strides
1554        #store
1555    };
1556
1557    TokenStream::from(result)
1558}