exercises/src/exercises/rcchars.md
2026-04-09 12:56:15 +00:00

1.9 KiB

Owned Chars

Chars but keeping a strong reference (Rc) to the string.

# mod rcchars {
# pub struct RcChars { _rc: std::rc::Rc<String>, chars: std::mem::MaybeUninit<std::str::Chars<'static>> }
# impl Iterator for RcChars {
# type Item = char;
# fn next(&mut self) -> Option<Self::Item> { unsafe { self.chars.assume_init_mut() }.next() }
# }
# impl RcChars {
# pub fn from_rc(rc: std::rc::Rc<String>) -> Self {
# let mut new = Self { _rc: rc, chars: std::mem::MaybeUninit::uninit() };
# new.chars.write(unsafe { &*std::rc::Rc::as_ptr(&new._rc) }.chars());
# new
# }
# }
# impl From<std::rc::Rc<String>> for RcChars { fn from(value: std::rc::Rc<String>) -> Self { Self::from_rc(value) } }
# impl Drop for RcChars { fn drop(&mut self) { unsafe { self.chars.assume_init_drop() } } }
# }
# use std::rc::Rc;
# use rcchars::RcChars;
{
    let rc = Rc::new("abc".to_string());
    let rcc = RcChars::from(rc.clone());
    drop(rc);
    assert_eq!(rcc.collect::<Vec<_>>(), ['a', 'b', 'c']);
}
{
    let rc = Rc::new("abc".to_string());
    let rcc = RcChars::from(rc);
    let rcc = Box::new(rcc);
    assert_eq!(rcc.collect::<Vec<_>>(), ['a', 'b', 'c']);
}

Solutions

  • Implementation used in rattlescript.
  • Same solution but with some extra comments.
  • Another solution. I prefer this one.
  • There's an even simpler version that even an AI can generate (don't do that for unsafe code in production), but I dislike it for several reasons, even though it's mostly sound.