---
# System prepended metadata

title: HasA

---

# HasA

```rust=
/// A timer_list wrapper.
#[pin_data] // also need pin drop
struct Timer{
    #[pin]
    opaque: Opaque<bindings::timer_list>
}

/// Timeout is a sub trait of `Field`.
pub trait Timeout: Field<Type=Timer> {
    fn timeout(base: &(<Self as Field>::Base));
}

/// The actual C function pointer set when a timer is created.
/// It will be called when time is up.
extern "C" fn bridge<F: Timeout>(ptr: *mut timer_list) {
    // container_of!
    let t = unsafe { *(unproject::<F as Field>(ptr)) };
    F::timeout(t);
}

impl Timer {
    pub fn new<F: Timeout>(..) -> impl PinInit<Self> {
        pin_init!(Self {
            opaque <- Opaque::ffi_init(|timer_list| {
                unsafe {
                    bindings::init_timer_list(
                        ...,
                        bridge::<F>,
                    )
                }
            })
        })
    }
}

/// As long as "has a timer", you can schedule one, need
/// to specify which via `field_of!`.
impl<T> for T {
    fn schedule<F>(&self, timeout: Duration)
    where
        F: Timeout + Field<Base=T>,
    {
        let timer = project<F>(self);
        
        unsafe {
            bindings::mod_timer(timer, timeout.to_jiffies());
        }
        
    }
}

impl Foo {
    /// Different timers may share the same timeout function.
    pub fn timeout(&self) {
        todo!();
    }
}

impl Timeout for field_of!(Foo, timer) {
    fn timeout(foo: &Foo) {
        foo.timeout();
    }
}

impl Timeout for field_of!(Foo, timer2) {
    fn timeout(foo: &Foo) {
        foo.timeout();
    }
}

/// Consider we have a struct has two timers
#[pin_data]
struct Foo {
    x: X,
    y: Y,
    #[pin]
    timer: Timer,
    #[pin]
    timer2: Timer,
}

fn main() {
    stack_pin_init!(
        let foo = Foo {
            ..
            timer <- Timer::new::<field_of!(Foo, timer)>(..),
            timer2 <- Timer::new::<field_of!(Foo, timer2)>(..)
        }
    }
    
    foo.schedule::<field_of!(Foo, timer)>();
}
```