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:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user