I tried a more realistic "minimal" example below. This uses the "*mut pointer" approach. Note that so far I could only make it work by making FilterView
cloneable, which really is not a good thing.
trait Filter {
// Self and Complement must be disjunct, i.e.
// self.allowed(x) => !complement.allowed(x)
type Complement;
// checks if element passes filter
fn allowed(&self, x: usize) -> bool;
// creates the complement of the filter
fn complement(&self) -> Self::Complement;
}
// Only indices which are explicitly allowed pass
#[derive(Clone)]
struct RequireListFilter {
indices: Vec<usize>,
}
impl Filter for RequireListFilter {
type Complement = ForbidListFilter;
fn allowed(&self, x: usize) -> bool {
self.indices.contains(&x)
}
fn complement(&self) -> Self::Complement {
ForbidListFilter { indices: self.indices.clone() } // TODO avoid clone
}
}
// All indices which are not explicitly forbidden pass
#[derive(Clone)]
struct ForbidListFilter {
indices: Vec<usize>,
}
impl Filter for ForbidListFilter {
type Complement = RequireListFilter;
fn allowed(&self, x: usize) -> bool {
!self.indices.contains(&x)
}
fn complement(&self) -> Self::Complement {
RequireListFilter { indices: self.indices.clone() } // TODO avoid clone
}
}
// Only event indices pass
#[derive(Clone)]
struct EvenFilter;
impl Filter for EvenFilter {
type Complement = OddFilter;
fn allowed(&self, x: usize) -> bool { x % 2 == 0 }
fn complement(&self) -> Self::Complement {
OddFilter
}
}
// Only odd indices pass
#[derive(Clone)]
struct OddFilter;
impl Filter for OddFilter {
type Complement = EvenFilter;
fn allowed(&self, x: usize) -> bool { x % 2 == 1 }
fn complement(&self) -> Self::Complement {
EvenFilter
}
}
trait View {
fn try_get(&self, x: usize) -> Option<&f32>;
fn try_get_mut(&self, x: usize) -> Option<&mut f32>;
fn split<F: Filter>(self, filter: F) -> (FilterView<Self, F>, FilterView<Self, F::Complement>)
where Self: Clone;
fn get(&self, x: usize) -> &f32 { self.try_get(x).unwrap() }
fn get_mut(&self, x: usize) -> &mut f32 { self.try_get_mut(x).unwrap() }
}
#[derive(Clone)] // FIXME should not be Clone
struct FilterView<B, F> {
base: B,
filter: F,
}
impl<B: View, F: Filter> View for FilterView<B, F> {
fn try_get(&self, x: usize) -> Option<&f32> {
if !self.filter.allowed(x) {
None
} else {
self.base.try_get(x)
}
}
fn try_get_mut(&self, x: usize) -> Option<&mut f32> {
if !self.filter.allowed(x) {
None
} else {
self.base.try_get_mut(x)
}
}
fn split<F2: Filter>(self, filter: F2) -> (
FilterView<Self, F2>,
FilterView<Self, F2::Complement>
)
where Self: Clone
{
let complement = filter.complement();
(
FilterView {
base: self.clone(),
filter,
},
FilterView {
base: self,
filter: complement,
},
)
}
}
#[derive(Clone)] // FIXME should not be Clone
struct UnsafeDataView<'b> {
ptr: *mut Data,
marker: core::marker::PhantomData<&'b mut Data>,
}
impl<'d> View for UnsafeDataView<'d> {
fn try_get(&self, x: usize) -> Option<&f32> {
unsafe { (*self.ptr).data.get(x) }
}
fn try_get_mut(&self, x: usize) -> Option<&mut f32> {
if x < unsafe { (*self.ptr).data.len() } {
unsafe { (*self.ptr).data.get_mut(x) }
} else {
None
}
}
fn split<F2: Filter>(self, filter: F2) -> (
FilterView<Self, F2>,
FilterView<Self, F2::Complement>
) {
let complement = filter.complement();
(
FilterView {
base: self.clone(),
filter,
},
FilterView {
base: self,
filter: complement,
},
)
}
}
struct Data {
data: Vec<f32>,
}
impl Data {
// Note: Unlike `View` we cannot use `self` to prevent multiple splits as we
// cannot consume Data. Instead we use &mut self.
fn split<'d, F: Filter>(&'d mut self, filter: F) -> (
FilterView<UnsafeDataView<'d>, F>,
FilterView<UnsafeDataView<'d>, F::Complement>
) {
let ptr = self as *mut Data;
let complement = filter.complement();
(
FilterView {
base: UnsafeDataView { ptr, marker: core::marker::PhantomData },
filter,
},
FilterView {
base: UnsafeDataView { ptr, marker: core::marker::PhantomData },
filter: complement,
},
)
}
}
fn main() {
let mut data = Data { data: vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0] };
let (vl, vr) = data.split(EvenFilter);
let (vrl, vrr) = vr.split(ForbidListFilter { indices: vec![3] });
// data.data[3] = 0.0; -- not allowed as views capture data
println!("Before:");
for i in 0..10 {
println!("{i} | {:<10}| {:<10}| {:<10}",
format!("{:?}", vl.try_get(i)),
format!("{:?}", vrl.try_get(i)),
format!("{:?}", vrr.try_get(i)));
}
*vl.get_mut(2) = 0.1;
*vrl.get_mut(1) = 0.2;
*vrr.get_mut(3) = 0.3;
println!("After:");
for i in 0..10 {
println!("{i} | {:<10}| {:<10}| {:<10}",
format!("{:?}", vl.try_get(i)),
format!("{:?}", vrl.try_get(i)),
format!("{:?}", vrr.try_get(i)));
}
}