///|
struct Resource[T] {
  acquire : async () -> T
  release : (T) -> Unit noraise
}

///|
pub fn[T] Resource::Resource(
  acquire : async () -> T,
  release : (T) -> Unit noraise,
) -> Resource[T] {
  { acquire, release }
}

///|
pub async fn[T] Resource::acquire(self : Self[T]) -> T {
  (self.acquire)()
}

///|
pub fn[T] Resource::release(self : Self[T], resource : T) -> Unit noraise {
  (self.release)(resource)
}

///|
pub async fn[T, U] Resource::use_resource(
  self : Self[T],
  f : async (T) -> U,
) -> U {
  let resource = self.acquire()
  defer self.release(resource)
  f(resource)
}