     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65

    use crate::header::HeaderMap;

    // xor-shift
    #[cfg(not(target_arch = "wasm32"))]
    pub(crate) fn fast_random() -> u64 {
        use std::cell::Cell;
        use std::collections::hash_map::RandomState;
        use std::hash::{BuildHasher, Hasher};
        use std::num::Wrapping;

        thread_local! {
            static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
        }

        fn seed() -> u64 {
            let seed = RandomState::new();

            let mut out = 0;
            let mut cnt = 0;
            while out == 0 {
                cnt += 1;
                let mut hasher = seed.build_hasher();
                hasher.write_usize(cnt);
                out = hasher.finish();
            }
            out
        }

        RNG.with(|rng| {
            let mut n = rng.get();
            debug_assert_ne!(n.0, 0);
            n ^= n >> 12;
            n ^= n << 25;
            n ^= n >> 27;
            rng.set(n);
            n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
        })
    }

    pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
        // IntoIter of HeaderMap yields (Option<HeaderName>, HeaderValue).
        // The first time a name is yielded, it will be Some(name), and if
        // there are more values with the same name, the next yield will be
        // None.
        //
        // TODO: a complex exercise would be to optimize this to only
        // require 1 hash/lookup of the key, but doing something fancy
        // with header::Entry...

        let mut prev_name = None;
        for (key, value) in src {
            match key {
                Some(key) => {
                    dst.insert(key.clone(), value);
                    prev_name = Some(key);
                }
                None => match prev_name {
                    Some(ref key) => {
                        dst.append(key.clone(), value);
                    }
                    None => unreachable!("HeaderMap::into_iter yielded None first"),
                },
            }
        }
    }