Last active
April 9, 2022 15:22
-
-
Save leophys/1d693070605286ae1978fdc2b9ec0a57 to your computer and use it in GitHub Desktop.
recursion-rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=103552fa9928fa268693038e9aa783d1