// Polonius (relaxed Rust A2): NLL rejects these (stable rustc: E0499 / E0502 / E0506), Polonius accepts // them: the borrow returned on one path is not live on the other. Relaxed crates check clean; strict // crates keep NLL's errors. main() runs every case (the behaviour is plain Rust's). use std::collections::{BTreeMap, HashMap}; // NLL problem case #3 (rust-lang/rust#21906): get-or-insert through a match fn get_default<'r>(map: &'r mut HashMap, key: u32) -> &'r mut String { match map.get_mut(&key) { Some(value) => value, None => { map.insert(key, String::new()); map.get_mut(&key).unwrap() } } } // conditional early return of the borrow fn get_or_insert<'a>(map: &'a mut HashMap>, key: &str) -> &'a mut Vec { if let Some(v) = map.get_mut(key) { return v; } map.insert(key.to_string(), Vec::new()); map.get_mut(key).unwrap() } // a shared lookup returned on the hit path, a mutation on the miss path fn cached<'a>(map: &'a mut BTreeMap, n: u64) -> &'a u64 { if let Some(v) = map.get(&n) { return v; } map.insert(n, n * n); map.get(&n).unwrap() } struct Interner { names: HashMap, misses: u32 } impl Interner { // the map is a field of `self` fn name(&mut self, id: u32) -> &mut String { if let Some(s) = self.names.get_mut(&id) { return s; } self.misses += 1; self.names.insert(id, format!("#{id}")); self.names.get_mut(&id).unwrap() } } // not a map lookup: no exact rewrite, the acceptance is reported fn first_positive(v: &mut Vec) -> &mut i32 { if let Some(x) = v.iter_mut().find(|x| **x > 0) { return x; } v.push(1); v.last_mut().unwrap() } // the returned borrow is conditional on a test of the borrowed value fn last_positive_or_push(v: &mut Vec) -> &mut i32 { if let Some(x) = v.last_mut() { if *x > 0 { return x; } } v.push(7); v.last_mut().unwrap() } // rust-lang/rust#46859 (Decoder): a loop that returns a borrow from one iteration and borrows again // in the next struct Reader { data: Vec, pos: usize } impl Reader { fn fill(&mut self) -> &[u8] { self.pos += 1; &self.data[..self.pos] } fn word(&mut self) -> &[u8] { loop { let buf = self.fill(); if let Some(w) = word_end(buf) { return w; } } } } fn word_end(b: &[u8]) -> Option<&[u8]> { if b.last() == Some(&b' ') { Some(&b[..b.len() - 1]) } else { None } } fn main() { let mut m = HashMap::new(); get_default(&mut m, 1).push('a'); get_default(&mut m, 1).push('b'); assert_eq!(m[&1], "ab"); let mut g = HashMap::new(); get_or_insert(&mut g, "k").push(3); get_or_insert(&mut g, "k").push(4); assert_eq!(g["k"], [3, 4]); let mut c = BTreeMap::new(); assert_eq!(*cached(&mut c, 9), 81); assert_eq!(*cached(&mut c, 9), 81); let mut i = Interner { names: HashMap::new(), misses: 0 }; i.name(5).push('!'); assert_eq!(i.name(5), "#5!"); assert_eq!(i.misses, 1); let mut v = vec![-1, 2]; *first_positive(&mut v) += 10; assert_eq!(v, [-1, 12]); let mut w = vec![-3]; assert_eq!(*last_positive_or_push(&mut w), 7); let mut r = Reader { data: b"abc def".to_vec(), pos: 0 }; assert_eq!(r.word(), b"abc"); println!("polonius_accept ok"); }