mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-28 13:31:14 +00:00
feat(no_std)!: option to disable layout cache for no_std
compatibility (#1795)
Resolves #1780 BREAKING CHANGE: Disabling `default-features` will now disable layout cache, which can have a negative impact on performance. `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only available if `layout-cache` feature is enabled.
This commit is contained in:
parent
09173d1829
commit
ab48c06171
@ -20,6 +20,8 @@ This is a quick summary of the sections below:
|
||||
- `Backend` now uses `Self::Error` for error handling instead of `std::io::Error`
|
||||
- `Terminal<B>` now uses `B::Error` for error handling instead of `std::io::Error`
|
||||
- `TestBackend` now uses `core::convert::Infallible` for error handling instead of `std::io::Error`
|
||||
- Disabling `default-features` will now disable layout cache, which can have a negative impact on performance
|
||||
- `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only available if `layout-cache` feature is enabled
|
||||
- [v0.29.0](#v0290)
|
||||
- `Sparkline::data` takes `IntoIterator<Item = SparklineBar>` instead of `&[u64]` and is no longer const
|
||||
- Removed public fields from `Rect` iterators
|
||||
@ -84,6 +86,26 @@ This is a quick summary of the sections below:
|
||||
|
||||
## Unreleased (0.30.0)
|
||||
|
||||
### `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only available if `layout-cache` feature is enabled ([#1795])
|
||||
|
||||
[#1795]: https://github.com/ratatui/ratatui/pull/1795
|
||||
|
||||
Previously, `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` were available independently of
|
||||
enabled feature flags.
|
||||
|
||||
### Disabling `default-features` will now disable layout cache, which can have a negative impact on performance ([#1795])
|
||||
|
||||
[#1795]: https://github.com/ratatui/ratatui/pull/1795
|
||||
|
||||
Layout cache is now opt-in in `ratatui-core` and enabled by default in `ratatui`. If app doesn't
|
||||
make use of `no_std`-compatibility, and disables `default-feature`, it is recommended to explicitly
|
||||
re-enable layout cache. Not doing so may impact performance.
|
||||
|
||||
```diff
|
||||
- ratatui = { version = "0.29.0", default-features = false }
|
||||
+ ratatui = { version = "0.30.0", default-features = false, features = ["layout-cache"] }
|
||||
```
|
||||
|
||||
### `TestBackend` now uses `core::convert::Infallible` for error handling instead of `std::io::Error` ([#1823])
|
||||
|
||||
[#1823]: https://github.com/ratatui/ratatui/pull/1823
|
||||
|
@ -24,6 +24,12 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
[features]
|
||||
default = []
|
||||
|
||||
## enables std
|
||||
std = []
|
||||
|
||||
## enables layout cache
|
||||
layout-cache = ["std"]
|
||||
|
||||
## enables conversions to / from colors, modifiers, and styles in the ['anstyle'] crate
|
||||
anstyle = ["dep:anstyle"]
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
use alloc::format;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::RefCell;
|
||||
use core::iter;
|
||||
use core::num::NonZeroUsize;
|
||||
use std::{dbg, thread_local};
|
||||
use std::dbg;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
@ -39,8 +38,9 @@ type Cache = LruCache<(Rect, Layout), (Segments, Spacers)>;
|
||||
// calculations.
|
||||
const FLOAT_PRECISION_MULTIPLIER: f64 = 100.0;
|
||||
|
||||
thread_local! {
|
||||
static LAYOUT_CACHE: RefCell<Cache> = RefCell::new(Cache::new(
|
||||
#[cfg(feature = "layout-cache")]
|
||||
std::thread_local! {
|
||||
static LAYOUT_CACHE: core::cell::RefCell<Cache> = core::cell::RefCell::new(Cache::new(
|
||||
NonZeroUsize::new(Layout::DEFAULT_CACHE_SIZE).unwrap(),
|
||||
));
|
||||
}
|
||||
@ -188,6 +188,8 @@ impl Layout {
|
||||
/// bit more to make it a round number. This gives enough entries to store a layout for every
|
||||
/// row and every column, twice over, which should be enough for most apps. For those that need
|
||||
/// more, the cache size can be set with [`Layout::init_cache()`].
|
||||
/// This const is unused if layout cache is disabled.
|
||||
#[cfg(feature = "layout-cache")]
|
||||
pub const DEFAULT_CACHE_SIZE: usize = 500;
|
||||
|
||||
/// Creates a new layout with default values.
|
||||
@ -280,8 +282,9 @@ impl Layout {
|
||||
/// grows until `cache_size` is reached.
|
||||
///
|
||||
/// By default, the cache size is [`Self::DEFAULT_CACHE_SIZE`].
|
||||
#[cfg(feature = "layout-cache")]
|
||||
pub fn init_cache(cache_size: NonZeroUsize) {
|
||||
LAYOUT_CACHE.with_borrow_mut(|c| c.resize(cache_size));
|
||||
LAYOUT_CACHE.with_borrow_mut(|cache| cache.resize(cache_size));
|
||||
}
|
||||
|
||||
/// Set the direction of the layout.
|
||||
@ -653,11 +656,18 @@ impl Layout {
|
||||
/// );
|
||||
/// ```
|
||||
pub fn split_with_spacers(&self, area: Rect) -> (Segments, Spacers) {
|
||||
LAYOUT_CACHE.with_borrow_mut(|c| {
|
||||
let key = (area, self.clone());
|
||||
c.get_or_insert(key, || self.try_split(area).expect("failed to split"))
|
||||
.clone()
|
||||
})
|
||||
let split = || self.try_split(area).expect("failed to split");
|
||||
|
||||
#[cfg(feature = "layout-cache")]
|
||||
{
|
||||
LAYOUT_CACHE.with_borrow_mut(|cache| {
|
||||
let key = (area, self.clone());
|
||||
cache.get_or_insert(key, split).clone()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "layout-cache"))]
|
||||
split()
|
||||
}
|
||||
|
||||
fn try_split(&self, area: Rect) -> Result<(Segments, Spacers), AddConstraintError> {
|
||||
@ -1200,14 +1210,15 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "layout-cache")]
|
||||
fn cache_size() {
|
||||
LAYOUT_CACHE.with_borrow(|c| {
|
||||
assert_eq!(c.cap().get(), Layout::DEFAULT_CACHE_SIZE);
|
||||
LAYOUT_CACHE.with_borrow(|cache| {
|
||||
assert_eq!(cache.cap().get(), Layout::DEFAULT_CACHE_SIZE);
|
||||
});
|
||||
|
||||
Layout::init_cache(NonZeroUsize::new(10).unwrap());
|
||||
LAYOUT_CACHE.with_borrow(|c| {
|
||||
assert_eq!(c.cap().get(), 10);
|
||||
LAYOUT_CACHE.with_borrow(|cache| {
|
||||
assert_eq!(cache.cap().get(), 10);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,10 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
#!
|
||||
## By default, we enable the crossterm backend as this is a reasonable choice for most applications
|
||||
## as it is supported on Linux/Mac/Windows systems. We also enable the `underline-color` feature
|
||||
## which allows you to set the underline color of text and the `macros` feature which provides
|
||||
## some useful macros.
|
||||
default = ["crossterm", "underline-color", "all-widgets", "macros"]
|
||||
## which allows you to set the underline color of text, the `macros` feature which provides
|
||||
## some useful macros and `layout-cache` which speeds up layout cache calculations
|
||||
## in `std`-enabled environments.
|
||||
default = ["crossterm", "underline-color", "all-widgets", "macros", "layout-cache"]
|
||||
#! Generally an application will only use one backend, so you should only enable one of the following features:
|
||||
## enables the [`CrosstermBackend`](backend::CrosstermBackend) backend and adds a dependency on [`crossterm`].
|
||||
crossterm = ["dep:ratatui-crossterm"]
|
||||
@ -48,6 +49,9 @@ serde = [
|
||||
"ratatui-termwiz?/serde",
|
||||
]
|
||||
|
||||
## enables layout cache
|
||||
layout-cache = ["ratatui-core/layout-cache"]
|
||||
|
||||
## enables conversions from colors in the [`palette`] crate to [`Color`](crate::style::Color).
|
||||
palette = ["ratatui-core/palette", "dep:palette"]
|
||||
|
||||
|
@ -54,6 +54,15 @@ impl Run for TestBackend {
|
||||
Backend::Termion => "termion",
|
||||
Backend::Termwiz => "termwiz",
|
||||
};
|
||||
// This is a temporary hack to run tests both with and without layout cache.
|
||||
// https://github.com/ratatui/ratatui/issues/1820
|
||||
run_cargo(vec![
|
||||
"test",
|
||||
"--all-targets",
|
||||
"--no-default-features",
|
||||
"--features",
|
||||
format!("{backend},layout-cache").as_str(),
|
||||
])?;
|
||||
run_cargo(vec![
|
||||
"test",
|
||||
"--all-targets",
|
||||
|
Loading…
x
Reference in New Issue
Block a user