feat: add loading animation example

Add a busy-wait sleep on a monotonic clock and re-export String,
format!, and Duration from the library. The example animates a
progress bar with a spinner and logs each step in a Vec<String>.

Co-Authored-By: qwen (lmstudio/qwen3.8-27b@q3_k_xl): wrote example
This commit is contained in:
2026-09-05 05:09:50 +02:00
parent cd1c9ab97d
commit b7f9fefd78
5 changed files with 117 additions and 13 deletions
+3
View File
@@ -5,9 +5,12 @@ extern crate alloc;
pub mod io;
pub mod runtime;
pub use alloc::format;
pub use alloc::string::String;
pub use alloc::vec;
pub use alloc::vec::Vec;
pub use core::result::Result;
pub use core::time::Duration;
#[macro_export]
macro_rules! print {
+51
View File
@@ -2,11 +2,26 @@ use core::alloc::{GlobalAlloc, Layout};
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use core::time::Duration;
#[cfg(unix)]
#[repr(C)]
struct Timespec {
tv_sec: i64,
tv_nsec: i64,
}
// CLOCK_MONOTONIC for the supported Unix targets.
#[cfg(all(unix, target_os = "macos"))]
const CLOCK_MONOTONIC: i32 = 4;
#[cfg(all(unix, not(target_os = "macos")))]
const CLOCK_MONOTONIC: i32 = 1;
#[cfg(unix)]
unsafe extern "C" {
fn malloc(size: usize) -> *mut u8;
fn free(pointer: *mut u8);
fn clock_gettime(clock_id: i32, ts: *mut Timespec) -> i32;
}
#[cfg(windows)]
@@ -15,6 +30,8 @@ unsafe extern "system" {
fn HeapAlloc(heap: *mut u8, flags: u32, bytes: usize) -> *mut u8;
fn HeapFree(heap: *mut u8, flags: u32, pointer: *mut u8) -> i32;
fn ExitProcess(status: u32) -> !;
fn QueryPerformanceCounter(counter: *mut i64) -> i32;
fn QueryPerformanceFrequency(frequency: *mut i64) -> i32;
}
pub struct SystemAllocator;
@@ -71,6 +88,40 @@ pub fn exit(status: u32) -> ! {
unsafe { ExitProcess(status) }
}
fn now() -> Duration {
#[cfg(unix)]
{
let mut ts = Timespec { tv_sec: 0, tv_nsec: 0 };
if unsafe { clock_gettime(CLOCK_MONOTONIC, &mut ts) } == 0 && ts.tv_sec >= 0 {
return Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32);
}
Duration::ZERO
}
#[cfg(windows)]
{
let mut counter: i64 = 0;
let mut frequency: i64 = 0;
if unsafe { QueryPerformanceCounter(&mut counter) } != 0
&& unsafe { QueryPerformanceFrequency(&mut frequency) } != 0
&& frequency > 0
{
let nanos = (counter as u128 * 1_000_000_000u128) / frequency as u128;
return Duration::from_nanos(nanos as u64);
}
Duration::ZERO
}
}
// Busy-wait sleep on a monotonic clock. The executor has no reactor yet,
// so the platform cannot block us; spinning is the only correct option.
pub fn sleep(duration: Duration) {
let deadline = now() + duration;
while now() < deadline {
core::hint::spin_loop();
}
}
fn clone_waker(_: *const ()) -> RawWaker {
RawWaker::new(core::ptr::null(), &WAKER_VTABLE)
}