Skip to content

Instantly share code, notes, and snippets.

@ekimekim
Created July 17, 2020 21:01
Show Gist options
  • Save ekimekim/6a4e09729f5599ba5e7f8b85913f7e5c to your computer and use it in GitHub Desktop.
Save ekimekim/6a4e09729f5599ba5e7f8b85913f7e5c to your computer and use it in GitHub Desktop.
// Proof of concept for exploring an idea I had with using rust's type system
// to manage the di/ei instructions on a Gameboy (if I ever get rust-on-gb working).
// It works as follows: We have a zero-sized IntFlag object. It's zero sized
// because it is NOT actually maintaining the state. It mediates access to the state
// at compile time by being borrowed.
// Each function that MAY disable interrupts (either in itself or a child func) must
// take a &mut IntFlag. It can then borrow that for an IntDisableGuard,
// as long as it releases it before the original borrow's lifetime expires (ie. by returning).
mod int_disable {
// zero-sized singleton that is borrowed to mediate access
// TODO prevent more than 1 of these being constructed
pub struct IntFlag;
// Guard object that disables interrupts for its lifetime
pub struct IntDisableGuard<'a>{
_flag: &'a mut IntFlag
}
impl IntFlag {
// Disables interrupts for the lifetime of the returned IntDisableGuard
pub fn disable(&mut self) -> IntDisableGuard {
println!("Disabled interrupts");
IntDisableGuard { _flag: self }
}
}
impl<'a> Drop for IntDisableGuard<'a> {
fn drop(&mut self) {
println!("Enabled interrupts");
}
}
}
fn main() {
let mut flag = int_disable::IntFlag{};
middle(&mut flag);
}
fn middle(flag: &mut int_disable::IntFlag) {
disables(flag);
{
let guard = flag.disable();
// disables(flag); // does not compile
must_be_already_disabled(&guard);
releases(guard);
}
disables(flag);
}
fn disables(flag: &mut int_disable::IntFlag) {
println!("before");
{
let _disabled = flag.disable();
println!("held");
}
println!("after");
}
fn must_be_already_disabled(_guard: &int_disable::IntDisableGuard) {
println!("while disabled");
}
fn releases(_guard: int_disable::IntDisableGuard) {
println!("releasing");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment