You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

67 lines
1.9 KiB
Rust

/// A UI backend API.
///
/// You won't see any instances of this trait as it exists purely within the
/// type system. Its sole purpose is to differentiate between individual
/// [`Render`] implementations for the respective UI backends.
pub trait Backend: Send + 'static {
/// Parameter passed to [`Render::render()`].
type Context;
/// Successful return type for [`Render::render()`].
type Output: Combine;
/// Error return type for [`Render::render()`]
type Error;
/// The backend's name (for debug messages).
/// Should be all lowercase and match the name of the feature flag.
fn name() -> &'static str;
}
pub type RenderResult<B> = Result<Option<<B as Backend>::Output>, <B as Backend>::Error>;
pub trait Combine: Sized {
fn combine(self, other: Self) -> Self;
}
impl Combine for () {
fn combine(self, _other: Self) -> Self {}
}
/// A UI component that can be rendered with a backend.
pub trait Render<B: Backend> {
/// Render this component in the context provided by the backend.
fn render(&self, context: &mut B::Context) -> RenderResult<B>;
}
/// The backend we're compiling against.
pub type TargetBackend = StubBackend;
/// Stub backend for testing.
pub struct StubBackend;
impl Backend for StubBackend {
type Context = ();
type Output = ();
type Error = ();
fn name() -> &'static str {
"stub"
}
}
// FIXME: We can't write a generic impl of Render<StubBackend> for any T that
// is View<StubBackend> because it would result in a cyclic dependency
// (Render<T> is a supertrait of View<T>)
macro_rules! stub_render_impl {
($name:ident) => {
impl Render<StubBackend> for crate::view::$name {
fn render(&self, _context: &mut ()) -> RenderResult<StubBackend> {
Ok(Some(()))
}
}
};
}
stub_render_impl!(Button);
stub_render_impl!(Text);
stub_render_impl!(VStack);
stub_render_impl!(HStack);