use ratatui_core::widgets::StatefulWidget;
use crate::buffer::Buffer;
use crate::layout::Rect;
#[instability::unstable(feature = "widget-ref")]
pub trait StatefulWidgetRef {
type State: ?Sized;
fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State);
}
impl<W, State: ?Sized> StatefulWidgetRef for &W
where
for<'a> &'a W: StatefulWidget<State = State>,
{
type State = State;
fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
self.render(area, buf, state);
}
}
#[cfg(test)]
mod tests {
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use rstest::{fixture, rstest};
use super::*;
use crate::buffer::Buffer;
use crate::layout::Rect;
use crate::text::Line;
use crate::widgets::Widget;
#[fixture]
fn buf() -> Buffer {
Buffer::empty(Rect::new(0, 0, 20, 1))
}
#[fixture]
fn state() -> String {
"world".to_string()
}
struct PersonalGreeting;
impl StatefulWidget for &PersonalGreeting {
type State = String;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
Line::from(format!("Hello {state}")).render(area, buf);
}
}
#[rstest]
fn render_ref(mut buf: Buffer, mut state: String) {
let widget = &PersonalGreeting;
widget.render_ref(buf.area, &mut buf, &mut state);
assert_eq!(buf, Buffer::with_lines(["Hello world "]));
}
#[rstest]
fn box_render_ref(mut buf: Buffer, mut state: String) {
let widget = Box::new(&PersonalGreeting);
widget.render_ref(buf.area, &mut buf, &mut state);
assert_eq!(buf, Buffer::with_lines(["Hello world "]));
}
#[rstest]
fn render_stateful_widget_ref_with_unsized_state(mut buf: Buffer) {
struct Bytes;
impl StatefulWidgetRef for Bytes {
type State = [u8];
fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
let slice = core::str::from_utf8(state).unwrap();
Line::from(format!("Bytes: {slice}")).render(area, buf);
}
}
let widget = Bytes;
let state = b"hello";
widget.render_ref(buf.area, &mut buf, &mut state.clone());
assert_eq!(buf, Buffer::with_lines(["Bytes: hello "]));
}
#[rstest]
fn render_stateful_widget_with_unsized_state(mut buf: Buffer) {
struct Bytes;
impl StatefulWidget for &Bytes {
type State = [u8];
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
let slice = core::str::from_utf8(state).unwrap();
Line::from(format!("Bytes: {slice}")).render(area, buf);
}
}
let widget = &Bytes;
let mut state = b"hello".to_owned();
let state = state.as_mut_slice();
widget.render_ref(buf.area, &mut buf, state);
assert_eq!(buf, Buffer::with_lines(["Bytes: hello "]));
}
}