Hello everyone.
I'm currently trying (and struggling) to write a function which acts on an iterator, and returns another iterator.
The types I'm dealing with are complex, since it's this kind of enum
, where one of the possible values contains a vector of the enum
type (see below) Playground here
#[derive(Clone, Debug, Eq, PartialEq)]
enum Gate {
Simple(u64, u64, u64),
Function(Vec<u64>, Vec<u64>, Vec<Gate>),
}
Then I have a function which iterates over a slice of Gate
s, and returns an iterator Iterator<Item=Gate>
where each value is a modified version of the gate given as parameter.
fn translate_gates<'s>(gates: &'s [Gate], output_input: &'s [u64], translated_gates: &'s mut usize) -> impl Iterator<Item = Gate> + 's {
gates
.iter()
.map(move |gate| translate_gate(gate, output_input, translated_gates))
}
fn translate_gate(gate: &Gate, output_input: &[u64], translated_gates: &mut usize) -> Gate {
match gate {
Simple(out, in1, in2) => {
*translated_gates += 1;
Simple(output_input[*out as usize], output_input[*in1 as usize], output_input[*in2 as usize])
}
Function(outs, ins, gates) => {
*translated_gates += 1;
let translated_outputs = outs.iter().map(|&val| output_input[val as usize]).collect();
let translated_inputs = ins.iter().map(|&val| output_input[val as usize]).collect();
Function(translated_outputs, translated_inputs, gates.clone())
}
}
}
These functions work as well.
But then I would like to write a function that flatten a list of Gate
s (let's call it a circuit), ie replacing all occurrences of Gate::Function
by their somewhat translated sub-circuit (it may be called recursively). And I want a Iterator
over the flattened subcircuit, since it might be huge.
The flattening function is recursive, and may return a std::iter::Once
if a Simple
gate is encountered, or a Map
in the other case.
I tried many things using Box
/ Cloning
the gates / additional lifetime specifiers... but I am still failing to make it work.
I know Rust lifetimes is maybe the most discussed topic, but still I was not able to find any answer...
Here is my last attempt:
fn flatten_gates<'a>(
// gates: impl Iterator<Item=&'a Gate> + 'a,
gates: &'a [Gate],
_not_used: &'a HashMap<String, u64>,
translated: &'a mut usize
) -> impl Iterator<Item=Gate> + 'a {
gates
.iter()
.flat_map(move |gate| -> Box<dyn Iterator<Item=Gate> + 'a> {
flatten(gate, _not_used, translated)
})
}
fn flatten<'a>(
gate: &'a Gate,
_not_used: &'a HashMap<String, u64>,
translated: &'a mut usize
) -> Box<dyn Iterator<Item=Gate> + 'a> {
match gate {
Simple(..) => Box::new(std::iter::once(gate.clone())),
Function(outs, ins, gates) => {
let output_inputs = [outs.to_vec(), ins.to_vec()].concat();
Box::new(
translate_gates(gates, &output_inputs, translated)
.flat_map(|inner_gate| flatten(&inner_gate, _not_used, translated))
)
}
}
}
Of course this is an overly simplified example compared to my use-case, but I tried to extract only the relevant parts relative to my issue.
Thanks for your help.