Have been trying to convert a (seemingly) straightforward loop:
let mut input = Input::new();
loop {
// fn read_line(&mut self) -> &str
let line = input.read_line();
if !line.is_empty() { ... }
}
Into an Iterator to opt into a for line in input { ... }.
The simplest/most intuitive way about it seems to (necessarily) involve unsafe.
Summary
impl Input {
pub fn lines(&mut self) -> impl Iterator<Item = &str> {
struct Lines<'i>(&'i mut Input);
impl<'i> Iterator for Lines<'i> {
type Item = &'i str;
fn next(&mut self) -> Option<Self::Item> {
match self.0.read_line() {
Err(e) => {
eprintln!("{e}");
None
}
Ok(line) => {
let ptr = line as *const str;
// SAFETY: the `&str` references the underlying `&'this mut Input`,
// not the local `&mut self`; extending the lifetime
// of the reference is safe by definition
Some(unsafe { &*ptr })
}
}
}
}
Lines(self)
}
pub fn read_line(&mut self) -> Res<&str> {
self.line.clear();
self.stdin.read_line(&mut self.line)?;
Ok(self.line.trim())
}
pub fn new() -> Self {
Self {
stdin: std::io::stdin(),
line: String::new(),
}
}
}
pub struct Input {
stdin: Stdin,
line: String,
}
The closest safest alternative, on the other hand, appears to involve GATs and wrappers and lending iterators and god knows what else. Is there any safe alternative for this particular case?