diff --git a/src/cli.rs b/src/cli.rs index c741b944..3e6f0651 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -27,12 +27,11 @@ use { damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs, reexec::ReexecArgs, run_tagged::RunTaggedArgs, tree::TreeArgs, xwayland::XwaylandArgs, }, - compositor::start_compositor, + compositor::{LogLevel, start_compositor}, format::{Format, ref_formats}, portal, pr_caps::drop_all_pr_caps, }, - ::log::Level, clap::{Args, Parser, Subcommand, ValueEnum, ValueHint, builder::PossibleValue}, clap_complete::Shell, }; @@ -50,7 +49,7 @@ struct Jay { pub struct GlobalArgs { /// The log level. #[clap(value_enum, long, default_value_t)] - pub log_level: CliLogLevel, + pub log_level: LogLevel, } #[derive(Subcommand, Debug)] @@ -176,7 +175,7 @@ pub struct LogArgs { pub struct SetLogArgs { /// The new log level. #[clap(value_enum)] - level: CliLogLevel, + level: LogLevel, } #[derive(Args, Debug)] @@ -194,28 +193,6 @@ pub enum CliBackend { Metal, } -#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default)] -pub enum CliLogLevel { - Trace, - Debug, - #[default] - Info, - Warn, - Error, -} - -impl Into for CliLogLevel { - fn into(self) -> Level { - match self { - CliLogLevel::Trace => Level::Trace, - CliLogLevel::Debug => Level::Debug, - CliLogLevel::Info => Level::Info, - CliLogLevel::Warn => Level::Warn, - CliLogLevel::Error => Level::Error, - } - } -} - #[derive(Args, Debug)] pub struct GenerateArgs { /// The shell to generate completions for diff --git a/src/cli/clients.rs b/src/cli/clients.rs index 64e1c8b3..c045245b 100644 --- a/src/cli/clients.rs +++ b/src/cli/clients.rs @@ -67,7 +67,7 @@ struct KillIdArgs { } pub fn main(global: GlobalArgs, clients_args: ClientsArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let clients = Rc::new(Clients { tc: tc.clone() }); clients.run(clients_args).await; }); diff --git a/src/cli/color_management.rs b/src/cli/color_management.rs index edae33ca..d23235cb 100644 --- a/src/cli/color_management.rs +++ b/src/cli/color_management.rs @@ -26,7 +26,7 @@ pub enum ColorManagementCmd { } pub fn main(global: GlobalArgs, args: ColorManagementArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let cm = ColorManagement { tc: tc.clone() }; cm.run(args).await; }); diff --git a/src/cli/damage_tracking.rs b/src/cli/damage_tracking.rs index 70b8d432..68a27851 100644 --- a/src/cli/damage_tracking.rs +++ b/src/cli/damage_tracking.rs @@ -55,7 +55,7 @@ pub struct DecayArgs { } pub fn main(global: GlobalArgs, damage_tracking_args: DamageTrackingArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let damage_tracking = Rc::new(DamageTracking { tc: tc.clone() }); damage_tracking.run(damage_tracking_args).await; }); diff --git a/src/cli/idle.rs b/src/cli/idle.rs index 9bc190ce..d2c001e4 100644 --- a/src/cli/idle.rs +++ b/src/cli/idle.rs @@ -51,7 +51,7 @@ pub struct IdleSetGracePeriodArgs { } pub fn main(global: GlobalArgs, args: IdleArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let idle = Idle { tc: tc.clone() }; idle.run(args).await; }); diff --git a/src/cli/input.rs b/src/cli/input.rs index 62e76487..887293a8 100644 --- a/src/cli/input.rs +++ b/src/cli/input.rs @@ -324,7 +324,7 @@ pub struct UseHardwareCursorArgs { } pub fn main(global: GlobalArgs, args: InputArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let idle = Rc::new(Input { tc: tc.clone() }); idle.run(args).await; }); diff --git a/src/cli/log.rs b/src/cli/log.rs index 2023daf6..ece70ae6 100644 --- a/src/cli/log.rs +++ b/src/cli/log.rs @@ -18,7 +18,7 @@ use { }; pub fn main(global: GlobalArgs, args: LogArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let logger = Rc::new(Log { tc: tc.clone(), path: RefCell::new(None), diff --git a/src/cli/quit.rs b/src/cli/quit.rs index 5cb03d2d..13722ece 100644 --- a/src/cli/quit.rs +++ b/src/cli/quit.rs @@ -8,7 +8,7 @@ use { }; pub fn main(global: GlobalArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { run(tc).await; }); } diff --git a/src/cli/randr.rs b/src/cli/randr.rs index 9ec490b5..d6041d39 100644 --- a/src/cli/randr.rs +++ b/src/cli/randr.rs @@ -466,7 +466,7 @@ fn blend_space_possible_values() -> Vec { } pub fn main(global: GlobalArgs, args: RandrArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let idle = Rc::new(Randr { tc: tc.clone() }); idle.run(args).await; }); diff --git a/src/cli/reexec.rs b/src/cli/reexec.rs index c4049e83..0889fa3b 100644 --- a/src/cli/reexec.rs +++ b/src/cli/reexec.rs @@ -20,7 +20,7 @@ pub struct ReexecArgs { } pub fn main(global: GlobalArgs, reexec_args: ReexecArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let rexec = Rc::new(Reexec { tc: tc.clone() }); rexec.run(reexec_args).await; }); diff --git a/src/cli/run_privileged.rs b/src/cli/run_privileged.rs index 11a78355..16c9b7fc 100644 --- a/src/cli/run_privileged.rs +++ b/src/cli/run_privileged.rs @@ -10,7 +10,7 @@ use { }; pub fn main(global: GlobalArgs, args: RunPrivilegedArgs) { - Logger::install_stderr(global.log_level.into()); + Logger::install_stderr(global.log_level); if let Some(xrd) = xrd() { let mut wd = match std::env::var(WAYLAND_DISPLAY) { Ok(v) => v, diff --git a/src/cli/run_tagged.rs b/src/cli/run_tagged.rs index d2baa230..9e985bf3 100644 --- a/src/cli/run_tagged.rs +++ b/src/cli/run_tagged.rs @@ -21,7 +21,7 @@ pub struct RunTaggedArgs { } pub fn main(global: GlobalArgs, run_tagged_args: RunTaggedArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let run_tagged = Rc::new(RunTagged { tc: tc.clone() }); run_tagged.run(run_tagged_args).await; }); diff --git a/src/cli/screenshot.rs b/src/cli/screenshot.rs index 8e8894e6..7ffd5f63 100644 --- a/src/cli/screenshot.rs +++ b/src/cli/screenshot.rs @@ -30,7 +30,7 @@ use { }; pub fn main(global: GlobalArgs, args: ScreenshotArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let screenshot = Rc::new(Screenshot { tc: tc.clone(), args, diff --git a/src/cli/seat_test.rs b/src/cli/seat_test.rs index ce8404d0..69a9ba98 100644 --- a/src/cli/seat_test.rs +++ b/src/cli/seat_test.rs @@ -27,7 +27,7 @@ use { }; pub fn main(global: GlobalArgs, args: SeatTestArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let screenshot = Rc::new(SeatTest { tc: tc.clone(), args, diff --git a/src/cli/set_log_level.rs b/src/cli/set_log_level.rs index 97a00880..9587cc0f 100644 --- a/src/cli/set_log_level.rs +++ b/src/cli/set_log_level.rs @@ -4,11 +4,12 @@ use { tools::tool_client::{ToolClient, with_tool_client}, wire::jay_compositor::SetLogLevel, }, + linearize::Linearize, std::rc::Rc, }; pub fn main(global: GlobalArgs, args: SetLogArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let logger = Rc::new(Log { tc: tc.clone(), args, @@ -27,7 +28,7 @@ async fn run(log: Rc) { let comp = tc.jay_compositor().await; tc.send(SetLogLevel { self_id: comp, - level: log.args.level as u32, + level: log.args.level.linearize() as u32, }); tc.round_trip().await; } diff --git a/src/cli/tree.rs b/src/cli/tree.rs index 1ee94d93..670267e3 100644 --- a/src/cli/tree.rs +++ b/src/cli/tree.rs @@ -62,7 +62,7 @@ struct QueryWorkspaceNameArgs { } pub fn main(global: GlobalArgs, tree_args: TreeArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let comp = tc.jay_compositor().await; let tree = Rc::new(Tree { tc: tc.clone(), diff --git a/src/cli/unlock.rs b/src/cli/unlock.rs index d097f584..9e739399 100644 --- a/src/cli/unlock.rs +++ b/src/cli/unlock.rs @@ -8,7 +8,7 @@ use { }; pub fn main(global: GlobalArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let logger = Rc::new(Unlocker { tc: tc.clone() }); run(logger).await; }); diff --git a/src/cli/xwayland.rs b/src/cli/xwayland.rs index bdd0f16e..6b188072 100644 --- a/src/cli/xwayland.rs +++ b/src/cli/xwayland.rs @@ -39,7 +39,7 @@ pub enum CliScalingMode { } pub fn main(global: GlobalArgs, args: XwaylandArgs) { - with_tool_client(global.log_level.into(), |tc| async move { + with_tool_client(global.log_level, |tc| async move { let xwayland = Xwayland { tc: tc.clone() }; xwayland.run(args).await; }); diff --git a/src/compositor.rs b/src/compositor.rs index 04d9b058..5b2e08f1 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -84,8 +84,11 @@ use { wheel::{Wheel, WheelError}, }, ahash::AHashSet, + clap::ValueEnum, forker::ForkerProxy, - jay_config::_private::DEFAULT_SEAT_NAME, + jay_config::{_private::DEFAULT_SEAT_NAME, logging::LogLevel as ConfigLogLevel}, + linearize::Linearize, + log::LevelFilter, std::{ cell::{Cell, RefCell}, env, @@ -113,9 +116,9 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) { None }; let forker = create_forker(reaper_pid); - let portal = portal::run_from_compositor(global.log_level.into()); + let portal = portal::run_from_compositor(global.log_level); enable_profiler(); - let logger = Logger::install_compositor(global.log_level.into()); + let logger = Logger::install_compositor(global.log_level); let portal = match portal { Ok(p) => Some(p), Err(e) => { @@ -804,3 +807,52 @@ pub fn config_dir() -> Option { None } } + +#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default, Eq, PartialEq, Linearize)] +pub enum LogLevel { + Trace, + Debug, + #[default] + Info, + Warn, + Error, + Off, +} + +impl Into for LogLevel { + fn into(self) -> LevelFilter { + match self { + LogLevel::Trace => LevelFilter::Trace, + LogLevel::Debug => LevelFilter::Debug, + LogLevel::Info => LevelFilter::Info, + LogLevel::Warn => LevelFilter::Warn, + LogLevel::Error => LevelFilter::Error, + LogLevel::Off => LevelFilter::Off, + } + } +} + +impl From for LogLevel { + fn from(value: LevelFilter) -> Self { + match value { + LevelFilter::Trace => LogLevel::Trace, + LevelFilter::Debug => LogLevel::Debug, + LevelFilter::Info => LogLevel::Info, + LevelFilter::Warn => LogLevel::Warn, + LevelFilter::Error => LogLevel::Error, + LevelFilter::Off => LogLevel::Off, + } + } +} + +impl From for LogLevel { + fn from(value: ConfigLogLevel) -> Self { + match value { + ConfigLogLevel::Trace => LogLevel::Trace, + ConfigLogLevel::Debug => LogLevel::Debug, + ConfigLogLevel::Info => LogLevel::Info, + ConfigLogLevel::Warn => LogLevel::Warn, + ConfigLogLevel::Error => LogLevel::Error, + } + } +} diff --git a/src/config/handler.rs b/src/config/handler.rs index 4ff91fe0..ee9858de 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -66,7 +66,7 @@ use { }, }, keyboard::{Group, Keymap, mods::Modifiers, syms::KeySym}, - logging::LogLevel, + logging::LogLevel as ConfigLogLevel, theme::{BarPosition, colors::Colorable, sized::Resizable}, timer::Timer as JayTimer, video::{ @@ -263,17 +263,17 @@ impl ConfigProxyHandler { fn handle_log_request( &self, - level: LogLevel, + level: ConfigLogLevel, msg: &str, file: Option<&str>, line: Option, ) { let level = match level { - LogLevel::Error => Level::Error, - LogLevel::Warn => Level::Warn, - LogLevel::Info => Level::Info, - LogLevel::Debug => Level::Debug, - LogLevel::Trace => Level::Trace, + ConfigLogLevel::Error => Level::Error, + ConfigLogLevel::Warn => Level::Warn, + ConfigLogLevel::Info => Level::Info, + ConfigLogLevel::Debug => Level::Debug, + ConfigLogLevel::Trace => Level::Trace, }; let debug = fmt::from_fn(|fmt| { if let Some(file) = file { @@ -1849,17 +1849,8 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_set_log_level(&self, level: LogLevel) { - let level = match level { - LogLevel::Error => Level::Error, - LogLevel::Warn => Level::Warn, - LogLevel::Info => Level::Info, - LogLevel::Debug => Level::Debug, - LogLevel::Trace => Level::Trace, - }; - if let Some(logger) = &self.state.logger { - logger.set_level(level); - } + fn handle_set_log_level(&self, level: ConfigLogLevel) { + self.state.set_log_level(level.into()); } fn handle_grab(&self, kb: InputDevice, grab: bool) -> Result<(), CphError> { diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index 218d7c29..005179bc 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -1,7 +1,7 @@ use { crate::{ - cli::CliLogLevel, client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError, ClientId}, + compositor::LogLevel, globals::{Global, GlobalName}, ifs::{ jay_acceptor_request::JayAcceptorRequest, @@ -35,7 +35,7 @@ use { }, }, bstr::ByteSlice, - log::Level, + linearize::LinearizeExt, std::{cell::Cell, ops::Deref, rc::Rc, str::FromStr}, thiserror::Error, }; @@ -185,22 +185,10 @@ impl JayCompositorRequestHandler for JayCompositor { } fn set_log_level(&self, req: SetLogLevel, _slf: &Rc) -> Result<(), Self::Error> { - const ERROR: u32 = CliLogLevel::Error as u32; - const WARN: u32 = CliLogLevel::Warn as u32; - const INFO: u32 = CliLogLevel::Info as u32; - const DEBUG: u32 = CliLogLevel::Debug as u32; - const TRACE: u32 = CliLogLevel::Trace as u32; - let level = match req.level { - ERROR => Level::Error, - WARN => Level::Warn, - INFO => Level::Info, - DEBUG => Level::Debug, - TRACE => Level::Trace, - _ => return Err(JayCompositorError::UnknownLogLevel(req.level)), + let Some(level) = LogLevel::from_linear(req.level as usize) else { + return Err(JayCompositorError::UnknownLogLevel(req.level)); }; - if let Some(logger) = &self.client.state.logger { - logger.set_level(level); - } + self.client.state.set_log_level(level); Ok(()) } diff --git a/src/logger.rs b/src/logger.rs index 0a37c702..22c4118a 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,8 +1,11 @@ use { - crate::utils::{errorfmt::ErrorFmt, oserror::OsError}, + crate::{ + compositor::LogLevel, + utils::{atomic_enum::AtomicEnum, errorfmt::ErrorFmt, oserror::OsError}, + }, backtrace::Backtrace, bstr::BString, - log::{Level, Log, Metadata, Record}, + log::{LevelFilter, Log, Metadata, Record}, parking_lot::Mutex, std::{ cell::Cell, @@ -24,14 +27,15 @@ thread_local! { } pub struct Logger { - level: AtomicU32, + level: AtomicEnum, + filter: AtomicU32, path: Mutex>, _file: Mutex, file_fd: AtomicI32, } impl Logger { - pub fn install_stderr(level: Level) -> Arc { + pub fn install_stderr(level: LogLevel) -> Arc { let file = match uapi::fcntl_dupfd_cloexec(2, 0) { Ok(fd) => fd, Err(e) => { @@ -42,18 +46,20 @@ impl Logger { Self::install(level, b"STDERR", file) } - pub fn install_compositor(level: Level) -> Arc { + pub fn install_compositor(level: LogLevel) -> Arc { let (path, file) = open_log_file("jay"); Self::install(level, path.as_bytes(), file) } - pub fn install_pipe(file: OwnedFd, level: Level) -> Arc { + pub fn install_pipe(file: OwnedFd, level: LogLevel) -> Arc { Self::install(level, b"PIPE", file) } - fn install(level: Level, path: &[u8], file: OwnedFd) -> Arc { + fn install(level: LogLevel, path: &[u8], file: OwnedFd) -> Arc { + let filter: LevelFilter = level.into(); let slf = Arc::new(Self { - level: AtomicU32::new(level as _), + level: AtomicEnum::new(level), + filter: AtomicU32::new(filter as _), path: Mutex::new(Arc::new(path.to_vec().into())), file_fd: AtomicI32::new(file.raw()), _file: Mutex::new(file), @@ -62,14 +68,21 @@ impl Logger { logger: slf.clone(), })) .unwrap(); - log::set_max_level(level.to_level_filter()); + log::set_max_level(filter); set_panic_hook(); slf } - pub fn set_level(&self, level: Level) { - self.level.store(level as _, Relaxed); - log::set_max_level(level.to_level_filter()); + pub fn set_level(&self, level: LogLevel) { + let filter: LevelFilter = level.into(); + self.level.store(level, Relaxed); + self.filter.store(filter as _, Relaxed); + log::set_max_level(filter); + } + + #[expect(dead_code)] + pub fn level(&self) -> LogLevel { + self.level.load(Relaxed) } pub fn path(&self) -> Arc { @@ -166,11 +179,11 @@ struct LogWrapper { impl Log for LogWrapper { fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() as u32 <= self.logger.level.load(Relaxed) + metadata.level() as u32 <= self.logger.filter.load(Relaxed) } fn log(&self, record: &Record) { - if record.level() as u32 > self.logger.level.load(Relaxed) { + if record.level() as u32 > self.logger.filter.load(Relaxed) { return; } let mut buffer = BUFFER.get(); diff --git a/src/portal.rs b/src/portal.rs index b2b9f62e..0dedaf3d 100644 --- a/src/portal.rs +++ b/src/portal.rs @@ -11,6 +11,7 @@ use { async_engine::AsyncEngine, cli::GlobalArgs, cmm::cmm_manager::ColorManager, + compositor::LogLevel, dbus::{ BUS_DEST, BUS_PATH, DBUS_NAME_FLAG_DO_NOT_QUEUE, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER, Dbus, DbusSocket, @@ -44,7 +45,6 @@ use { wheel::Wheel, wire_dbus::org, }, - log::Level, std::{ ffi::OsStr, io::{BufReader, BufWriter}, @@ -64,7 +64,7 @@ const PORTAL_CANCELLED: u32 = 1; const PORTAL_ENDED: u32 = 2; pub fn run_freestanding(global: GlobalArgs) { - let logger = Logger::install_stderr(global.log_level.into()); + let logger = Logger::install_stderr(global.log_level); run(logger, true); } @@ -131,7 +131,7 @@ impl PortalStartup { } } -pub fn run_from_compositor(level: Level) -> Result { +pub fn run_from_compositor(level: LogLevel) -> Result { let Pipe { read, write } = match pipe() { Ok(p) => p, Err(e) => return Err(PortalError::CreatePipe(e)), diff --git a/src/state.rs b/src/state.rs index af28f4d0..9606d5dc 100644 --- a/src/state.rs +++ b/src/state.rs @@ -13,7 +13,7 @@ use { client::{Client, ClientCaps, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange}, clientmem::ClientMemOffset, cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager}, - compositor::LIBEI_SOCKET, + compositor::{LIBEI_SOCKET, LogLevel}, config::ConfigProxy, copy_device::CopyDeviceRegistry, cpu_worker::CpuWorker, @@ -1690,6 +1690,12 @@ impl State { self.explicit_sync_enabled.set(enabled); self.expose_new_singletons(); } + + pub fn set_log_level(&self, level: LogLevel) { + if let Some(logger) = &self.logger { + logger.set_level(level); + } + } } #[derive(Debug, Error)] diff --git a/src/tools/tool_client.rs b/src/tools/tool_client.rs index 0b720d5c..a4242a89 100644 --- a/src/tools/tool_client.rs +++ b/src/tools/tool_client.rs @@ -2,7 +2,7 @@ use { crate::{ async_engine::{AsyncEngine, SpawnedFuture}, client::{EventFormatter, RequestParser}, - compositor::WAYLAND_DISPLAY, + compositor::{LogLevel, WAYLAND_DISPLAY}, io_uring::{IoUring, IoUringError}, logger::Logger, object::{ObjectId, WL_DISPLAY_ID}, @@ -30,7 +30,6 @@ use { }, }, ahash::AHashMap, - log::Level, std::{ cell::{Cell, RefCell}, collections::VecDeque, @@ -97,7 +96,7 @@ pub struct ToolClient { jay_damage_tracking: Cell>>, } -pub fn with_tool_client(level: Level, f: F) +pub fn with_tool_client(level: LogLevel, f: F) where F: FnOnce(Rc) -> T + 'static, T: Future + 'static, @@ -111,7 +110,7 @@ fn handle_error(e: ToolClientError) -> ! { fatal!("Could not create a tool client: {}", ErrorFmt(e)); } -fn with_tool_client_(level: Level, f: F) -> Result<(), ToolClientError> +fn with_tool_client_(level: LogLevel, f: F) -> Result<(), ToolClientError> where F: FnOnce(Rc) -> T + 'static, T: Future + 'static, diff --git a/src/utils/atomic_enum.rs b/src/utils/atomic_enum.rs index 5fa00a83..45e50416 100644 --- a/src/utils/atomic_enum.rs +++ b/src/utils/atomic_enum.rs @@ -31,12 +31,10 @@ where } } - #[expect(dead_code)] pub fn load(&self, ordering: Ordering) -> T { unsafe { T::from_linear_unchecked(self.v.load(ordering)) } } - #[expect(dead_code)] pub fn store(&self, t: T, ordering: Ordering) { self.v.store(t.linearize(), ordering); }