I'm facing a difficult issue and I would appreciate any help.
I'm designing a code generator from a language to Rust, and let's assume I need a design like the one below
What I want to achieve is a kind of "pool" from which we can quantify and return a boolean, but the quantifier all/any is given as a boolean. So for the same range, I am able to achieve this using my own quantifier
method and the iter().all(
in the test.
Since this trait is local, I'd love to take any iterable and be able to use my quantifier function on it. In this example, I'm trying hard to emulate that behavior, but the third assertion has two problems:
- The type of the variables in the lambda has a double indirection (how to get rid of one indirection?)
- I get a strange issue "temporary value dropped while borrowed" which makes no sense to me, given that the whole expression is returning a boolean and
quantifier
andall
have the same self signature, except for the function to iterate.
My wish is to modify the design so that the last assertion compiles, and there is no double indirection.,
Link to the playground of the code below:
use std::{collections::HashSet, rc::Rc};
pub trait BoundedPool<T: 'static> {
// Takes ownership of the function because otherwise it's hard to
// generate code to create a function and borrow it immediately
// without assigning it to a variable first
fn quantifier(self: &mut Self, is_forall: bool, f: Rc<dyn Fn(&T) -> bool>) -> bool;
fn forall(self: &mut Self, f: Rc<dyn Fn(&T) -> bool>) -> bool {
self.quantifier(true, f)
}
fn exists(self: &mut Self, f: Rc<dyn Fn(&T) -> bool>) -> bool {
self.quantifier(false, f)
}
}
pub struct Range(pub HashSet<i32>);
impl Range {
pub fn new(start: i32, end: i32) -> Self {
let mut set = HashSet::new();
for i in start..end {
set.insert(i);
}
Self(set)
}
pub fn iter(&self) -> std::collections::hash_set::Iter<'_, i32> {
self.0.iter()
}
}
impl BoundedPool<i32> for Range {
fn quantifier(self: &mut Self, is_forall: bool, f: Rc<dyn Fn(&i32) -> bool>) -> bool {
for i in self.iter(){
if !f(i) == is_forall {
return !is_forall;
}
}
is_forall
}
}
impl <T:'static, W: 'static> BoundedPool<T> for W
where W: Iterator<Item = T> {
fn quantifier(mut self: &mut Self, is_forall: bool, f: Rc<dyn Fn(&T) -> bool>) -> bool {
if is_forall {
self.all(|x| f(&x))
} else {
self.any(|x| f(&x))
}
}
}
#[test]
fn test_difference() {
assert!(Range::new(1, 7).quantifier(true, Rc::new(|i: &i32| *i < 8)));
assert!(Range::new(1, 7).iter().all(Rc::new(|i: &i32| *i < 8).as_ref()));
assert!(Range::new(1, 7).iter().quantifier(true, Rc::new(|i: &&i32| **i < 8)));
}