//! This crate provides high-level APIs for accessing components provided by
//! [OpenComputers](https://oc.cil.li) in a vanilla Minecraft environment (e.g. redstone blocks,
//! GPUs, screens, etc.).
//!
//! As a general rule, APIs in this crate accept an `Invoker` and a `Buffer` scratch buffer, the
//! latter being used for encoding parameters and decoding return values. This buffer can be reused
//! between API calls to reduce heap allocations. In some cases the return value of an API may
//! borrow from the scratch buffer.
//!
//! # Important
//! You *must* depend on [`oc-wasm-futures`](https://gitlab.com/Hawk777/oc-wasm-futures) with the
//! `proper-waker` feature in your own application if your chosen executor requires the
//! `proper-waker` feature.
//!
//! # Example
//! ```
//! extern crate alloc;
//! use alloc::boxed::Box;
//! use alloc::string::String;
//! use alloc::vec::Vec;
//! use cassette::Cassette;
//! use oc_wasm_futures::sleep;
//! use oc_wasm_opencomputers::prelude::*;
//! use oc_wasm_opencomputers::{gpu, screen};
//! use oc_wasm_opencomputers::common::{Dimension, Point};
//! use oc_wasm_safe::{component, computer};
//! use once_cell::unsync::OnceCell;
//! use core::future::Future;
//! use core::panic::PanicInfo;
//! use core::pin::Pin;
//! use wee_alloc::WeeAlloc;
//!
//! #[global_allocator]
//! static ALLOC: WeeAlloc<'_> = WeeAlloc::INIT;
//!
//! fn panic_hook(info: &PanicInfo<'_>) {
//! if let Some(s) = info.payload().downcast_ref::<&str>() {
//! computer::error(s);
//! } else if let Some(s) = info.payload().downcast_ref::<String>() {
//! computer::error(s);
//! } else {
//! computer::error("panic occurred");
//! }
//! }
//!
//! async fn main_impl() -> Result<(), oc_wasm_opencomputers::error::Error> {
//! // Grab the one-and-only resources.
//! let mut invoker = component::Invoker::take().unwrap();
//! let mut lister = component::Lister::take().unwrap();
//!
//! // Find the GPU.
//! let mut listing = lister.start(Some("gpu"));
//! let gpu = *listing.next().expect("no GPU").address();
//! let gpu = gpu::Gpu::new(gpu);
//!
//! // Find the screen.
//! listing = lister.start(Some("screen"));
//! let screen = *listing.next().expect("no screen").address();
//! let screen = screen::Screen::new(screen);
//!
//! // Allocate a scratch buffer to use for method calls.
//! let mut buffer = Vec::<u8>::new();
//!
//! // Lock the GPU so method calls can be made on it. For gpu_locked’s lifetime, methods can only
//! // be called on the GPU, not on anything else. To make method calls on another component, drop
//! // this value and recreate it later.
//! let mut gpu_locked = gpu.lock(&mut invoker, &mut buffer);
//!
//! // Bind the GPU to the screen.
//! gpu_locked.bind(*screen.address(), true).await?;
//!
//! // Clear the screen.
//! gpu_locked.set_foreground(gpu::Colour::Rgb(gpu::Rgb(0x00_FF_FF_FF))).await?;
//! gpu_locked.set_background(gpu::Colour::Rgb(gpu::Rgb(0))).await?;
//! gpu_locked.fill(Point{x: 1, y: 1}, Dimension{width: 160, height: 80}, ' ').await?;
//!
//! // Say hello.
//! gpu_locked.set(Point{x: 1, y: 1}, "Hello World!", gpu::TextDirection::Horizontal).await?;
//!
//! // Stop running forever.
//! loop {
//! sleep::for_uptime(core::time::Duration::from_secs(3600)).await;
//! }
//! }
//!
//! async fn main() {
//! match main_impl().await {
//! Ok(()) => (),
//! Err(e) => computer::error(e.as_str()),
//! }
//! }
//!
//! #[no_mangle]
//! pub extern "C" fn run(_: i32) -> i32 {
//! static mut PANIC_HOOK_SET: bool = false;
//! static mut EXECUTOR: OnceCell<Cassette<Pin<Box<dyn Future<Output = ()>>>>> = OnceCell::new();
//!
//! // SAFETY: run() is not reentrant and never touches the PANIC_HOOK_SET variable anywhere else
//! // in its body, so run() will never create a second mutable reference. PANIC_HOOK_SET is local
//! // to run(), so nobody else can create a second mutable reference on the same thread. OC-Wasm
//! // is single-threaded, so no other threads can call run() at the same time.
//! let panic_hook_set = unsafe { &mut PANIC_HOOK_SET };
//! if !*panic_hook_set {
//! std::panic::set_hook(Box::new(panic_hook));
//! *panic_hook_set = true;
//! }
//!
//! // SAFETY: run() is not reentrant and never touches the EXECUTOR variable anywhere else in its
//! // body, so run() will never create a second mutable reference. EXECUTOR is local to run(), so
//! // nobody else can create a second mutable reference on the same thread. OC-Wasm is
//! // single-threaded, so no other threads can call run() at the same time.
//! let executor = unsafe { &mut EXECUTOR };
//! executor.get_or_init(|| Cassette::new(Box::pin(main())));
//! let executor = executor.get_mut().unwrap_or_else(
//! // SAFETY: We just called get_or_init(), so it must be populated.
//! || unsafe { core::hint::unreachable_unchecked() },
//! );
//!
//! sleep::check_for_wakeups();
//! if executor.poll_on().is_some() {
//! computer::error("main task terminated");
//! }
//! sleep::shortest_requested()
//! }
//! ```
// I’m not a big fan of this style, and it sometimes generates larger code.
// Nope, tabs thanks.
extern crate alloc;