Skip to content

Instantly share code, notes, and snippets.

@leophys
Last active April 9, 2022 15:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leophys/1d693070605286ae1978fdc2b9ec0a57 to your computer and use it in GitHub Desktop.
Save leophys/1d693070605286ae1978fdc2b9ec0a57 to your computer and use it in GitHub Desktop.
recursion-rs
// Playing with cons from https://doc.rust-lang.org/book/ch15-01-box.html
#[derive(Clone)]
pub enum Chain<T: Clone> {
Link(T, Box<Chain<T>>),
Nil,
}
impl<T: Clone> Chain<T> {
pub fn new(capacity: usize, initializer: T) -> Self {
let start = Self::Nil;
start.init(capacity, initializer)
}
fn init(self, i: usize, v: T) -> Self {
if i == 0 {
return Self::Link(v, Box::new(self));
}
let next = Self::Link(v.clone(), Box::new(self));
next.init(i - 1, v.clone())
}
pub fn get(&self, i: usize) -> T {
match self {
Self::Link(value, next) => {
if i == 0 {
return value.clone();
}
next.get(i - 1)
}
Self::Nil => panic!("out of bounds"),
}
}
pub fn set(mut self, i: usize, v: T) -> Self {
if i == 0 {
let next = match self {
Self::Link(_, next) => next.clone(),
Self::Nil => Box::new(Self::Nil),
};
self = Chain::Link(v.clone(), next);
return self;
}
let (t, next) = match self {
Self::Link(t, next) => (t.clone(), next.set(i - 1, v.clone())),
Self::Nil => panic!("out of bounds"),
};
self = Self::Link(t, Box::new(next));
self
}
}
#[derive(Clone)]
pub struct Ring<T: Clone> {
cap: usize,
cur: usize,
chain: Chain<Option<T>>,
}
impl<T: Clone> Ring<T> {
pub fn new(cap: usize) -> Self {
Self {
cap,
cur: 0,
chain: Chain::new(cap, None),
}
}
pub fn next(self) -> Self {
Self {
cap: self.cap,
cur: (self.cur + 1) % self.cap,
chain: self.chain,
}
}
pub fn next_mut(&mut self) {
self.cur = (self.cur + 1) % self.cap;
}
pub fn get(&self) -> Option<T> {
self.chain.get(self.cur)
}
pub fn set(self, v: Option<T>) -> Self {
Self {
cap: self.cap,
cur: self.cur,
chain: self.chain.set(self.cur, v),
}
}
}
#[test]
fn test_chain_get() {
let chain = Chain::Link(
1,
Box::new(Chain::Link(
2,
Box::new(Chain::Link(3, Box::new(Chain::Nil))),
)),
);
assert_eq!(chain.get(0), 1);
assert_eq!(chain.get(1), 2);
assert_eq!(chain.get(2), 3);
}
#[test]
fn test_chain_set() {
let chain = Chain::Link(
1,
Box::new(Chain::Link(
2,
Box::new(Chain::Link(3, Box::new(Chain::Nil))),
)),
);
let chain1 = chain.clone().set(0, 0);
let chain2 = chain.clone().set(1, 0);
let chain3 = chain.clone().set(2, 0);
assert_eq!(chain1.get(0), 0);
assert_eq!(chain1.get(1), 2);
assert_eq!(chain1.get(2), 3);
assert_eq!(chain2.get(0), 1);
assert_eq!(chain2.get(1), 0);
assert_eq!(chain2.get(2), 3);
assert_eq!(chain3.get(0), 1);
assert_eq!(chain3.get(1), 2);
assert_eq!(chain3.get(2), 0);
}
#[test]
fn test_ring() {
let mut ring: Ring<u32> = Ring::new(3);
for _i in 0..9 {
assert_eq!(ring.get(), None);
ring = ring.next();
}
let new_ring = ring
.set(Some(1))
.next()
.set(Some(2))
.next()
.set(Some(3))
.next();
assert_eq!(new_ring.clone().get(), Some(1));
assert_eq!(new_ring.clone().next().get(), Some(2));
assert_eq!(new_ring.clone().next().next().get(), Some(3));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment