Skip to content

Instantly share code, notes, and snippets.

@ekimekim
Created July 17, 2020 21:01
Show Gist options
  • Select an option

  • Save ekimekim/6a4e09729f5599ba5e7f8b85913f7e5c to your computer and use it in GitHub Desktop.

Select an option

Save ekimekim/6a4e09729f5599ba5e7f8b85913f7e5c to your computer and use it in GitHub Desktop.

Revisions

  1. ekimekim created this gist Jul 17, 2020.
    69 changes: 69 additions & 0 deletions int_flag.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@

    // 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");
    }