Skip to main content

apollo_federation/utils/
mod.rs

1//! This module contains various tools that help the ergonomics of this crate.
2
3mod fallible_iterator;
4pub(crate) mod human_readable;
5pub(crate) mod logging;
6pub(crate) mod multi_index_map;
7pub mod normalize_schema;
8pub(crate) mod serde_bridge;
9
10use std::cell::OnceCell;
11
12// Re-exports
13pub(crate) use fallible_iterator::*;
14pub(crate) use multi_index_map::MultiIndexMap;
15
16/// If the `iter` yields a single element, return it. Else return `None`.
17pub(crate) fn iter_into_single_item<T>(mut iter: impl Iterator<Item = T>) -> Option<T> {
18    let item = iter.next()?;
19    if iter.next().is_none() {
20        Some(item)
21    } else {
22        None
23    }
24}
25
26/// An alternative to Itertools' `max_by_key` which breaks ties by returning the first element with
27/// the maximum key, rather than the last.
28pub(crate) fn first_max_by_key<T, O: Ord>(
29    iter: impl Iterator<Item = T>,
30    f: impl Fn(&T) -> O,
31) -> Option<T> {
32    let mut iter = iter.peekable();
33    let first = iter.next()?;
34    let mut max_item = first;
35    let mut max_key = f(&max_item);
36
37    for item in iter {
38        let key = f(&item);
39        if key > max_key {
40            max_key = key;
41            max_item = item;
42        }
43    }
44
45    Some(max_item)
46}
47
48/// Wrapper around OnceCell that allows fallible instantiation.
49///
50/// NOTE: This is a temporary workaround until `OnceCell#get_or_try_init` stabilizes
51pub(crate) struct FallibleOnceCell<T>(OnceCell<T>);
52
53impl<T: std::fmt::Debug> FallibleOnceCell<T> {
54    pub(crate) fn new() -> Self {
55        Self(OnceCell::new())
56    }
57
58    pub(crate) fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
59    where
60        F: FnOnce() -> Result<T, E>,
61    {
62        let value = match self.0.get() {
63            Some(value) => value,
64            None => {
65                let value = f()?;
66                self.0.set(value).unwrap();
67                // we just set the value so this should never return None
68                self.0.get().unwrap()
69            }
70        };
71        Ok(value)
72    }
73}