wit-bindgen-moonbit 0.60.0

MoonBit bindings generator for WIT and the component model, typically used through the `wit-bindgen-cli` crate.
Documentation
// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
priv enum PromiseState[X] {
  Pending
  Completed(X)
  Failed(Error)
  Closed
  ReaderDropped
  Consumed
}

///|
priv struct PromiseCell[X] {
  mut state : PromiseState[X]
  ready : Semaphore
  cleanup : ((X) -> Unit)?
  mut reading : Bool
}

///|
/// The local producer side of a one-shot `Future[X]`.
///
/// This is a MoonBit coordination value, not a component-model future writable
/// endpoint. Conversion to a component future remains generated at an FFI site.
pub struct Promise[X] {
  priv cell : Ref[PromiseCell[X]]
}

///|
pub(all) suberror PromiseClosed derive(Debug)

///|
fn[X] new_future_promise(cleanup : ((X) -> Unit)?) -> (Future[X], Promise[X]) {
  let cell : Ref[PromiseCell[X]] = {
    val: {
      state: Pending,
      ready: Semaphore(1, initial_value=0),
      cleanup,
      reading: false,
    },
  }
  ({ inner: Promised(cell) }, { cell, })
}

///|
/// Create a local one-shot Future/Promise pair.
pub fn[X] Future::new() -> (Future[X], Promise[X]) {
  new_future_promise(None)
}

///|
/// Create a local one-shot Future/Promise pair with value-discard cleanup.
///
/// The cleanup callback runs when the promise completed successfully but the
/// future is dropped before consuming the value.
pub fn[X] Future::new_with_cleanup(
  cleanup : (X) -> Unit,
) -> (Future[X], Promise[X]) {
  new_future_promise(Some(cleanup))
}

///|
/// Complete the paired future with `value`.
///
/// `true` means the future accepted ownership. `false` means its reader was
/// already dropped and the caller retains ownership of `value`.
pub fn[X] Promise::complete(self : Promise[X], value : X) -> Bool {
  match self.cell.val.state {
    Pending => {
      self.cell.val.state = Completed(value)
      self.cell.val.ready.release()
      true
    }
    ReaderDropped => false
    Completed(_) | Failed(_) | Closed | Consumed =>
      abort("promise already settled")
  }
}

///|
/// Complete the paired future with an error raised by `Future::get`.
pub fn[X] Promise::fail(self : Promise[X], error : Error) -> Bool {
  match self.cell.val.state {
    Pending => {
      self.cell.val.state = Failed(error)
      self.cell.val.ready.release()
      true
    }
    ReaderDropped => false
    Completed(_) | Failed(_) | Closed | Consumed =>
      abort("promise already settled")
  }
}

///|
/// Close the paired future without producing a value.
///
/// A local waiter observes `PromiseClosed`. An outgoing component future still
/// cannot represent this terminal state and follows the bridge's no-value
/// failure policy if it has already crossed an FFI boundary.
pub fn[X] Promise::close(self : Promise[X]) -> Bool {
  match self.cell.val.state {
    Pending => {
      self.cell.val.state = Closed
      self.cell.val.ready.release()
      true
    }
    ReaderDropped => false
    Completed(_) | Failed(_) | Closed | Consumed =>
      abort("promise already settled")
  }
}

///|
fn[X] consume_promised_future(cell : Ref[PromiseCell[X]]) -> X raise {
  match cell.val.state {
    Completed(value) => {
      cell.val.state = Consumed
      value
    }
    Failed(error) => {
      cell.val.state = Consumed
      raise error
    }
    Closed => {
      cell.val.state = Consumed
      raise PromiseClosed
    }
    Pending => panic()
    ReaderDropped => raise Cancelled::Cancelled
    Consumed => abort("future already consumed")
  }
}

///|
async fn[X] promised_future_get(cell : Ref[PromiseCell[X]]) -> X {
  if cell.val.reading {
    abort("future read already in progress")
  }
  match cell.val.state {
    Pending => {
      cell.val.reading = true
      cell.val.ready.acquire() catch {
        err => {
          cell.val.reading = false
          if cell.val.state is Pending {
            cell.val.state = ReaderDropped
          }
          raise err
        }
      }
      cell.val.reading = false
      consume_promised_future(cell)
    }
    Completed(_) | Failed(_) | Closed => consume_promised_future(cell)
    ReaderDropped => consume_promised_future(cell)
    Consumed => abort("future already consumed")
  }
}

///|
fn[X] promised_future_drop(
  cell : Ref[PromiseCell[X]],
  fallback_cleanup : ((X) -> Unit)?,
) -> Unit {
  if cell.val.reading {
    match cell.val.state {
      Pending => {
        cell.val.state = ReaderDropped
        cell.val.ready.release()
      }
      // Once settlement assigned a result, the waiting reader owns it.
      Completed(_) | Failed(_) | Closed => ()
      ReaderDropped | Consumed => ()
    }
    return
  }
  match cell.val.state {
    Pending => cell.val.state = ReaderDropped
    Completed(value) => {
      cell.val.state = Consumed
      match cell.val.cleanup {
        Some(cleanup) => cleanup(value)
        None =>
          match fallback_cleanup {
            Some(cleanup) => cleanup(value)
            None => ()
          }
      }
    }
    Failed(_) | Closed => cell.val.state = Consumed
    ReaderDropped | Consumed => ()
  }
}