Info
This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: A pattern for flexible factory references using Deref newtypes
A pattern for flexible factory references using Deref newtypes
โ Rust ๐ 2025-09-15 ๐ค surdeus ๐๏ธ 1This post is generated via Grok because my english isnt good.
Hi everyone!
I've been tinkering with a way to handle "factory" types (like ranges) that create child items needing a back-reference to the factory. The trick is supporting different ref kindsโ&T
, Rc<T>
, etc.โwithout separate trait impls for each.
Rust's coherence rules block direct blanket impls, so I use a thin Deref
newtype wrapper. It's a twist on the classic newtype pattern, but handy for this. Thoughts? Useful? Already in a crate somewhere?
Here's a generic countable range. Items hold a Deref
ref to the range for bounds/indexing.
use std::ops::{Add, Deref, Range, RangeFrom, Sub};
use std::marker::PhantomData;
use std::fmt::Debug;
// Wrapper for any Deref<Target = Target>.
pub struct NTDeref<Ref, Target>(pub Ref, PhantomData<fn() -> Target>);
impl<Ref, Target> NTDeref<Ref, Target> {
pub fn new(r: Ref) -> Self { Self(r, PhantomData) }
}
pub trait ToNTDeref<Target>
where Self: Deref<Target = Target> + Sized {
fn as_nt_deref(self) -> NTDeref<Self, Target>;
}
impl<Ref, Target> ToNTDeref<Target> for Ref
where Ref: Deref<Target = Target> + Sized {
fn as_nt_deref(self) -> NTDeref<Self, Target> {
NTDeref::new(self)
}
}
// Item trait: iterate and index relative to a range.
pub trait CountableRangeItem: Sized {
fn next(self) -> Option<Self>;
fn index(&self) -> usize;
fn zero_assign(&mut self); // Reset to start.
}
// Factory trait: takes self by value (for ownership).
pub trait CountableRangeForRef {
type Item: CountableRangeItem;
fn item_first(self) -> Self::Item;
fn item_from_index(self, index: usize) -> Option<Self::Item>;
fn index_len(self) -> usize;
}
pub struct CountableRangeStd<T> { range: Range<T> }
pub struct CountableRangeStdItem<T, RangeRef>
where RangeRef: Deref<Target = CountableRangeStd<T>> {
item: T,
ref_range: RangeRef,
}
impl<T, RangeRef> Deref for CountableRangeStdItem<T, RangeRef>
where RangeRef: Deref<Target = CountableRangeStd<T>> {
type Target = T;
fn deref(&self) -> &Self::Target { &self.item }
}
impl<T, RangeRef> CountableRangeItem for CountableRangeStdItem<T, RangeRef>
where
RangeRef: Deref<Target = CountableRangeStd<T>>,
RangeFrom<T>: Iterator<Item = T>, // a super weird way to use `Step`
T: Copy + Ord + Sub<Output: TryInto<usize, Error: Debug>>,
{
fn next(self) -> Option<Self>
where
Self: Sized,
{
let mut for_step = RangeFrom { start: self.item };
let _for_step_res = for_step.next();
let v_next = for_step.start;
if v_next >= self.ref_range.range.end {
None
} else {
Some(Self {
item: v_next,
ref_range: self.ref_range,
})
}
}
fn index(&self) -> usize {
(self.item - self.ref_range.range.start).try_into().unwrap()
}
fn zero_assign(&mut self) {
self.item = self.ref_range.range.start;
}
}
impl<T, RangeRef> CountableRangeForRef for NTDeref<RangeRef,CountableRangeStd<T>>
//CountableRangeStd<T,RangeRef,ToNewRef>
where
RangeRef: Deref<Target = CountableRangeStd<T>>,
RangeFrom<T>: Iterator<Item = T>,
T: Copy + Ord + Sub<Output: TryInto<usize, Error: Debug>> + Add<Output = T>,
usize: TryInto<T, Error: Debug>,
{
type Item = CountableRangeStdItem<T, RangeRef>;
fn item_first(self) -> Self::Item {
CountableRangeStdItem {
item: self.0.range.start,
ref_range: self.0, //.clone()
}
}
fn item_from_index(self, index: usize) -> Option<Self::Item> {
let real_idx = index.try_into().unwrap() + self.0.range.start;
if real_idx >= self.0.range.end {
None
} else {
Some(CountableRangeStdItem {
item: real_idx,
ref_range: self.0, //.clone()
})
}
}
fn index_len(self) -> usize {
(self.0.range.end - self.0.range.start).try_into().unwrap()
}
}
struct Meme;
struct MemeItem;
impl CountableRangeItem for MemeItem {
fn next(self)->Option<Self> where Self: Sized {
todo!()
}
fn index(&self)->usize {
todo!()
}
fn zero_assign(&mut self) {
todo!()
}
}
impl<RangeRef> CountableRangeForRef for NTDeref<RangeRef,Meme>
where
RangeRef: Deref<Target = CountableRangeStd<Meme>>,
{
type Item=MemeItem;
fn item_first(self)->Self::Item {
todo!()
}
fn item_from_index(self,index:usize)->Option<Self::Item> {
todo!()
}
fn index_len(self)->usize {
todo!()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::rc::Rc;
#[test]
fn flexible_refs() {
let range = CountableRangeStd { range: -2i32..2 };
fn check<Ref: Deref<Target = CountableRangeStd<i32>>>(
mut item: CountableRangeStdItem<i32, Ref>,
) {
assert_eq!(*item, -2);
item = item.next().unwrap(); assert_eq!(*item, -1);
item = item.next().unwrap(); assert_eq!(*item, 0);
item = item.next().unwrap(); assert_eq!(*item, 1);
assert!(item.next().is_none());
}
// &T
check((&range).as_nt_deref().item_first());
let outer_item;
{
let rc = Rc::new(range);
let inner_item=rc.clone().as_nt_deref().item_first();
outer_item=rc.clone().as_nt_deref().item_first();
check(inner_item);
}
// Rc<T>
check(outer_item);
}
}
.as_nt_deref()
, get a single blanket impl.*item
).self
(ok for factories).Could extend to iterators or builders. Any tweaks for idiomatic Rust? Cheers!
2 posts - 2 participants
๐ท๏ธ Rust_feed