1
0
Fork 0
forked from wry/wry

all: fetch current time only once per iteration

This commit is contained in:
Julian Orth 2024-07-11 17:39:18 +02:00
parent d8d6be1ef3
commit bb9e6ba3b5
21 changed files with 99 additions and 97 deletions

View file

@ -5,6 +5,7 @@ pub use {crate::async_engine::ae_yield::Yield, ae_task::SpawnedFuture};
use {
crate::{
async_engine::ae_task::Runnable,
time::Time,
utils::{array, numcell::NumCell, syncqueue::SyncQueue},
},
std::{
@ -33,6 +34,7 @@ pub struct AsyncEngine {
stash: RefCell<VecDeque<Runnable>>,
yield_stash: RefCell<VecDeque<Waker>>,
stopped: Cell<bool>,
now: Cell<Option<Time>>,
}
impl AsyncEngine {
@ -45,6 +47,7 @@ impl AsyncEngine {
stash: Default::default(),
yield_stash: Default::default(),
stopped: Cell::new(false),
now: Default::default(),
})
}
@ -84,6 +87,7 @@ impl AsyncEngine {
let mut stash = self.stash.borrow_mut();
let mut yield_stash = self.yield_stash.borrow_mut();
while self.num_queued.get() > 0 {
self.now.take();
self.iteration.fetch_add(1);
let mut phase = 0;
while phase < NUM_PHASES {
@ -119,4 +123,15 @@ impl AsyncEngine {
fn iteration(&self) -> u64 {
self.iteration.get()
}
pub fn now(&self) -> Time {
match self.now.get() {
Some(t) => t,
None => {
let now = Time::now_unchecked();
self.now.set(Some(now));
now
}
}
}
}

View file

@ -29,7 +29,6 @@ use {
},
logind::{LogindError, Session},
state::State,
time::now_usec,
udev::{Udev, UdevError, UdevMonitor},
utils::{
clonecell::{CloneCell, UnsafeCellCloneSafe},
@ -469,7 +468,7 @@ impl MetalInputDevice {
}
fn pre_pause(&self) {
let time_usec = now_usec();
let time_usec = self.state.now_usec();
for (key, _) in self.pressed_keys.take() {
self.event(InputEvent::Key {
time_usec,

View file

@ -18,7 +18,6 @@ use {
renderer::RenderResult,
state::State,
theme::Color,
time::now_nsec,
tree::OutputNode,
udev::UdevDevice,
utils::{
@ -591,7 +590,7 @@ impl MetalConnector {
});
if let Some(delta) = *DELTA {
let next_present = self.next_flip_nsec.get().saturating_sub(delta);
if now_nsec() < next_present {
if self.state.now_nsec() < next_present {
self.state.ring.timeout(next_present).await.unwrap();
}
}

View file

@ -12,7 +12,6 @@ use {
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
renderer::RenderResult,
state::State,
time::now_usec,
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
queue::AsyncQueue, syncqueue::SyncQueue,
@ -818,7 +817,7 @@ impl XBackend {
inverted: false,
});
seat.mouse_event(InputEvent::AxisFrame {
time_usec: now_usec(),
time_usec: self.state.now_usec(),
});
}
} else {
@ -834,7 +833,7 @@ impl XBackend {
n => BTN_SIDE + n - 8,
};
seat.mouse_event(InputEvent::Button {
time_usec: now_usec(),
time_usec: self.state.now_usec(),
button,
state,
});
@ -851,7 +850,7 @@ impl XBackend {
let event: XiKeyPress = event.parse()?;
if let Some(seat) = self.seats.get(&event.deviceid) {
seat.kb_event(InputEvent::Key {
time_usec: now_usec(),
time_usec: self.state.now_usec(),
key: event.detail - 8,
state,
});
@ -885,7 +884,7 @@ impl XBackend {
self.mouse_seats.get(&event.deviceid),
) {
seat.mouse_event(InputEvent::ConnectorPosition {
time_usec: now_usec(),
time_usec: self.state.now_usec(),
connector: win.id,
x: Fixed::from_1616(event.event_x),
y: Fixed::from_1616(event.event_y),
@ -904,7 +903,7 @@ impl XBackend {
_ => return Ok(()),
};
seat.mouse_event(InputEvent::ConnectorPosition {
time_usec: now_usec(),
time_usec: self.state.now_nsec(),
connector: win.id,
x: Fixed::from_1616(event.event_x),
y: Fixed::from_1616(event.event_y),

View file

@ -3,7 +3,6 @@ use {
async_engine::Phase,
client::{Client, ClientError},
object::ObjectId,
time::Time,
utils::{
buffd::{BufFdIn, BufFdOut, MsgParser},
errorfmt::ErrorFmt,
@ -11,7 +10,7 @@ use {
},
},
futures_util::{select, FutureExt},
std::{collections::VecDeque, mem, rc::Rc},
std::{collections::VecDeque, mem, rc::Rc, time::Duration},
};
pub async fn client(data: Rc<Client>) {
@ -112,7 +111,7 @@ async fn send(data: Rc<Client>) {
swapchain.commit();
mem::swap(&mut swapchain.pending, &mut buffers);
}
let timeout = Time::in_ms(5000).unwrap();
let timeout = data.state.now() + Duration::from_millis(5000);
while let Some(mut cur) = buffers.pop_front() {
out.flush(&mut cur, timeout).await?;
data.swapchain.borrow_mut().free.push(cur);

View file

@ -1,5 +1,6 @@
use {
crate::{
async_engine::AsyncEngine,
fixed::Fixed,
format::ARGB8888,
gfx_api::{AcquireSync, GfxContext, GfxError, GfxTexture, ReleaseSync},
@ -283,13 +284,14 @@ impl ServerCursorTemplate {
}
}
pub fn instantiate(&self, size: u32) -> Rc<dyn Cursor> {
pub fn instantiate(&self, state: &State, size: u32) -> Rc<dyn Cursor> {
match &self.var {
ServerCursorTemplateVariant::Static(s) => Rc::new(StaticCursor {
image: s.for_size(size),
}),
ServerCursorTemplateVariant::Animated(a) => Rc::new(AnimatedCursor {
start: Time::now_unchecked(),
start: state.now(),
eng: state.eng.clone(),
next: NumCell::new(a[0].delay_ns),
idx: Cell::new(0),
images: a.iter().map(|c| c.for_size(size)).collect(),
@ -424,6 +426,7 @@ impl Cursor for StaticCursor {
struct AnimatedCursor {
start: Time,
eng: Rc<AsyncEngine>,
next: NumCell<u64>,
idx: Cell<usize>,
images: Vec<InstantiatedCursorImage>,
@ -463,7 +466,7 @@ impl Cursor for AnimatedCursor {
}
fn tick(&self) {
let dist = Time::now_unchecked() - self.start;
let dist = self.eng.now() - self.start;
if (dist.as_nanos() as u64) < self.next.get() {
return;
}
@ -478,7 +481,7 @@ impl Cursor for AnimatedCursor {
}
fn time_until_tick(&self) -> Duration {
let dist = Time::now_unchecked() - self.start;
let dist = self.eng.now() - self.start;
let dist = dist.as_nanos() as u64;
let nanos = self.next.get().saturating_sub(dist);
Duration::from_nanos(nanos)

View file

@ -296,7 +296,9 @@ impl CursorUser {
KnownCursor::ZoomIn => &cursors.zoom_in,
KnownCursor::ZoomOut => &cursors.zoom_out,
};
self.set_cursor2(Some(tpl.instantiate(self.group.size.get())));
self.set_cursor2(Some(
tpl.instantiate(&self.group.state, self.group.size.get()),
));
}
fn set_output(&self, output: &Rc<OutputNode>) {

View file

@ -5,7 +5,6 @@ use {
ifs::ext_idle_notification_v1::ExtIdleNotificationV1,
leaks::Tracker,
object::{Object, Version},
time::now_usec,
utils::errorfmt::ErrorFmt,
wire::{ext_idle_notifier_v1::*, ExtIdleNotifierV1Id},
},
@ -81,7 +80,7 @@ impl ExtIdleNotifierV1RequestHandler for ExtIdleNotifierV1 {
async fn run(n: Rc<ExtIdleNotificationV1>) {
loop {
let now = now_usec();
let now = n.client.state.now_usec();
let elapsed = now.saturating_sub(n.seat.last_input());
if elapsed < n.duration_usec {
let res = n

View file

@ -68,7 +68,6 @@ use {
object::{Object, Version},
rect::Rect,
state::{DeviceHandlerData, State},
time::now_usec,
tree::{
generic_node_visitor, ContainerNode, ContainerSplit, Direction, FoundNode, Node,
OutputNode, ToplevelNode, WorkspaceNode,
@ -245,7 +244,7 @@ impl WlSeatGlobal {
changes: NumCell::new(CHANGE_CURSOR_MOVED | CHANGE_TREE),
constraint: Default::default(),
idle_notifications: Default::default(),
last_input_usec: Cell::new(now_usec()),
last_input_usec: Cell::new(state.now_usec()),
wlr_data_devices: Default::default(),
text_inputs: Default::default(),
text_input: Default::default(),

View file

@ -1,8 +1,5 @@
use {
crate::{
fixed::Fixed, ifs::wl_seat::WlSeatGlobal, time::now_usec, tree::Node,
utils::clonecell::CloneCell,
},
crate::{fixed::Fixed, ifs::wl_seat::WlSeatGlobal, tree::Node, utils::clonecell::CloneCell},
std::rc::Rc,
};
@ -179,7 +176,7 @@ struct SwipeGesture {
impl GestureOwner for SwipeGesture {
fn revert_to_default(&self, seat: &Rc<WlSeatGlobal>) {
self.swipe_end(seat, now_usec(), true);
self.swipe_end(seat, seat.state.now_usec(), true);
}
fn swipe_update(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, dx: Fixed, dy: Fixed) {
@ -199,7 +196,7 @@ struct PinchGesture {
impl GestureOwner for PinchGesture {
fn revert_to_default(&self, seat: &Rc<WlSeatGlobal>) {
self.pinch_end(seat, now_usec(), true);
self.pinch_end(seat, seat.state.now_usec(), true);
}
fn pinch_update(
@ -228,7 +225,7 @@ struct HoldGesture {
impl GestureOwner for HoldGesture {
fn revert_to_default(&self, seat: &Rc<WlSeatGlobal>) {
self.hold_end(seat, now_usec(), true);
self.hold_end(seat, seat.state.now_usec(), true);
}
fn hold_end(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, cancelled: bool) {

View file

@ -17,7 +17,6 @@ use {
wl_surface::WlSurface,
},
object::Version,
time::now_usec,
tree::{FoundNode, Node},
utils::{
bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap,
@ -328,7 +327,7 @@ impl WlSeatGlobal {
return;
};
for tool in tablet.tools.lock().drain_values() {
self.tablet_handle_remove_tool(now_usec(), tool.id);
self.tablet_handle_remove_tool(tablet.seat.state.now_usec(), tool.id);
}
for pad in tablet.pads.lock().drain_values() {
pad.pad_owner.destroy(&pad);
@ -366,7 +365,7 @@ impl WlSeatGlobal {
if self.tablet.tools.is_empty() {
return;
}
let now = now_usec();
let now = self.state.now_usec();
for tool in self.tablet.tools.lock().values() {
tool.tool_owner.apply_changes(tool, now, None);
}

View file

@ -13,7 +13,7 @@ use {
},
wl_surface::WlSurface,
},
time::{now_usec, usec_to_msec},
time::usec_to_msec,
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
},
std::{cell::Cell, rc::Rc},
@ -192,7 +192,7 @@ impl TabletPad {
pub fn surface_enter(self: &Rc<Self>, n: &WlSurface) {
let mut serial = n.client.pending_serial();
let time = usec_to_msec(now_usec());
let time = n.client.state.now_msec() as u32;
self.for_each_pair(n, |tablet, pad| {
pad.send_enter(serial.get(), &tablet, n);
for group in &self.groups {

View file

@ -1,7 +1,6 @@
use {
crate::{
ifs::wl_seat::tablet::{PadButtonState, TabletPad},
time::now_usec,
tree::Node,
utils::{clonecell::CloneCell, smallmap::SmallMap},
},
@ -42,7 +41,9 @@ impl PadOwnerHolder {
}
pub fn destroy(&self, pad: &Rc<TabletPad>) {
self.owner.get().revert_to_default(pad, now_usec());
self.owner
.get()
.revert_to_default(pad, pad.seat.state.now_usec());
let prev = pad.node.set(pad.seat.state.root.clone());
prev.node_on_tablet_pad_leave(pad);
prev.node_seat_state().remove_tablet_pad_focus(pad);
@ -53,7 +54,9 @@ impl PadOwnerHolder {
}
pub fn focus_root(&self, pad: &Rc<TabletPad>) {
self.owner.get().revert_to_default(pad, now_usec());
self.owner
.get()
.revert_to_default(pad, pad.seat.state.now_usec());
let node = pad.seat.state.root.clone();
pad.focus_node(node);
}

View file

@ -2,7 +2,6 @@ use {
crate::{
fixed::Fixed,
ifs::wl_seat::tablet::{TabletTool, TabletToolChanges, ToolButtonState},
time::now_usec,
tree::{FindTreeUsecase, FoundNode, Node},
utils::{clonecell::CloneCell, smallmap::SmallMap},
},
@ -35,14 +34,15 @@ impl ToolOwnerHolder {
pub fn destroy(&self, tool: &Rc<TabletTool>) {
let root = tool.tablet.seat.state.root.clone();
let prev = tool.node.set(root);
prev.node_on_tablet_tool_leave(tool, now_usec());
prev.node_on_tablet_tool_leave(tool, tool.tablet.seat.state.now_usec());
prev.node_seat_state().remove_tablet_tool_focus(tool);
}
pub fn focus_root(&self, tool: &Rc<TabletTool>) {
self.owner.set(self.default.clone());
let root = tool.tablet.seat.state.root.clone();
tool.set_node(root, now_usec());
let state = &tool.tablet.seat.state;
let root = state.root.clone();
tool.set_node(root, state.now_usec());
}
pub fn button(

View file

@ -15,7 +15,6 @@ use {
test_error::TestResult, test_gfx_api::TestGfxCtx, test_utils::test_expected_event::TEEH,
},
state::State,
time::now_usec,
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, on_change::OnChange, oserror::OsError,
syncqueue::SyncQueue,
@ -75,6 +74,7 @@ impl TestBackend {
chm
},
name: Rc::new("default-mouse".to_string()),
state: state.clone(),
},
transform_matrix: Cell::new([[1.0, 0.0], [0.0, 1.0]]),
accel_speed: Cell::new(1.0),
@ -93,6 +93,7 @@ impl TestBackend {
chm
},
name: Rc::new("default-keyboard".to_string()),
state: state.clone(),
},
});
let mode = Mode {
@ -273,7 +274,7 @@ pub struct TestMouseClick {
impl Drop for TestMouseClick {
fn drop(&mut self) {
self.mouse.common.event(InputEvent::Button {
time_usec: now_usec(),
time_usec: self.mouse.common.state.now_usec(),
button: self.button,
state: KeyState::Released,
});
@ -291,7 +292,7 @@ pub struct TestBackendMouse {
impl TestBackendMouse {
pub fn rel(&self, dx: f64, dy: f64) {
self.common.event(InputEvent::Motion {
time_usec: now_usec(),
time_usec: self.common.state.now_usec(),
dx: Fixed::from_f64(dx * self.accel_speed.get()),
dy: Fixed::from_f64(dy * self.accel_speed.get()),
dx_unaccelerated: Fixed::from_f64(dx),
@ -301,7 +302,7 @@ impl TestBackendMouse {
pub fn abs(&self, connector: &TestConnector, x: f64, y: f64) {
self.common.event(InputEvent::ConnectorPosition {
time_usec: now_usec(),
time_usec: self.common.state.now_usec(),
connector: connector.id,
x: Fixed::from_f64(x),
y: Fixed::from_f64(y),
@ -310,7 +311,7 @@ impl TestBackendMouse {
pub fn click(self: &Rc<Self>, button: u32) -> TestMouseClick {
self.common.event(InputEvent::Button {
time_usec: now_usec(),
time_usec: self.common.state.now_usec(),
button,
state: KeyState::Pressed,
});
@ -330,7 +331,7 @@ impl TestBackendMouse {
inverted: false,
});
self.common.event(InputEvent::AxisFrame {
time_usec: now_usec(),
time_usec: self.common.state.now_usec(),
});
}
@ -348,7 +349,7 @@ impl TestBackendMouse {
inverted,
});
self.common.event(InputEvent::AxisFrame {
time_usec: now_usec(),
time_usec: self.common.state.now_usec(),
});
}
}
@ -365,7 +366,7 @@ pub struct PressedKey {
impl Drop for PressedKey {
fn drop(&mut self) {
self.kb.common.event(InputEvent::Key {
time_usec: now_usec(),
time_usec: self.kb.common.state.now_usec(),
key: self.key,
state: KeyState::Released,
});
@ -375,7 +376,7 @@ impl Drop for PressedKey {
impl TestBackendKb {
pub fn press(self: &Rc<Self>, key: u32) -> PressedKey {
self.common.event(InputEvent::Key {
time_usec: now_usec(),
time_usec: self.common.state.now_usec(),
key,
state: KeyState::Pressed,
});
@ -421,6 +422,7 @@ pub struct TestInputDeviceCommon {
pub on_change: CloneCell<Option<Rc<dyn Fn()>>>,
pub capabilities: CopyHashMap<InputDeviceCapability, ()>,
pub name: Rc<String>,
pub state: Rc<State>,
}
impl TestInputDeviceCommon {

View file

@ -3,7 +3,6 @@ use {
backend::KeyState,
ifs::wl_seat::wl_keyboard,
it::{test_error::TestError, test_object::TestObject, test_transport::TestTransport},
time::now_usec,
wire::{zwp_virtual_keyboard_v1::*, ZwpVirtualKeyboardV1Id},
},
std::{cell::Cell, io::Write, rc::Rc},
@ -50,7 +49,7 @@ impl TestVirtualKeyboard {
};
self.tran.send(Key {
self_id: self.id,
time: (now_usec() / 1000) as u32,
time: self.tran.run.state.now_msec() as u32,
key,
state,
})

View file

@ -60,6 +60,7 @@ use {
scale::Scale,
security_context_acceptor::SecurityContextAcceptors,
theme::{Color, Theme},
time::Time,
tree::{
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds,
NodeVisitorBase, OutputNode, PlaceholderNode, ToplevelNode, ToplevelNodeBase,
@ -1061,6 +1062,23 @@ impl State {
}
(self.dummy_output.get().unwrap(), 0, 0)
}
pub fn now(&self) -> Time {
self.eng.now()
}
pub fn now_nsec(&self) -> u64 {
self.eng.now().nsec()
}
pub fn now_usec(&self) -> u64 {
self.eng.now().usec()
}
#[allow(dead_code)]
pub fn now_msec(&self) -> u64 {
self.eng.now().msec()
}
}
#[derive(Debug, Error)]

View file

@ -5,16 +5,9 @@ use {
ops::{Add, Sub},
time::Duration,
},
thiserror::Error,
uapi::c,
};
#[derive(Debug, Error)]
pub enum TimeError {
#[error("clock_gettime failed: {0}")]
ClockGettime(crate::utils::oserror::OsError),
}
#[derive(Copy, Clone)]
pub struct Time(pub c::timespec);
@ -28,20 +21,6 @@ impl Debug for Time {
}
impl Time {
pub fn now() -> Result<Time, TimeError> {
let mut time = uapi::pod_zeroed();
if let Err(e) = uapi::clock_gettime(c::CLOCK_MONOTONIC, &mut time) {
return Err(TimeError::ClockGettime(e.into()));
}
Ok(Self(time))
}
pub fn in_ms(ms: u64) -> Result<Time, TimeError> {
let now = Self::now()?;
Ok(now + Duration::from_millis(ms))
}
#[allow(dead_code)]
pub fn now_unchecked() -> Time {
let mut time = uapi::pod_zeroed();
let _ = uapi::clock_gettime(c::CLOCK_MONOTONIC, &mut time);
@ -73,6 +52,12 @@ impl Time {
let nsec = self.0.tv_nsec as u64 / 1_000;
sec + nsec
}
pub fn msec(self) -> u64 {
let sec = self.0.tv_sec as u64 * 1_000;
let nsec = self.0.tv_nsec as u64 / 1_000_000;
sec + nsec
}
}
impl Eq for Time {}
@ -124,14 +109,6 @@ impl Add<Duration> for Time {
}
}
pub fn now_nsec() -> u64 {
Time::now_unchecked().nsec()
}
pub fn now_usec() -> u64 {
Time::now_unchecked().usec()
}
pub fn usec_to_msec(usec: u64) -> u32 {
(usec / 1000) as u32
}

View file

@ -29,7 +29,6 @@ use {
scale::Scale,
state::State,
text::{self, TextTexture},
time::Time,
tree::{
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
NodeId, StackedNode, WorkspaceNode,
@ -164,7 +163,7 @@ impl OutputNode {
if self.screencopies.is_empty() {
return;
}
let now = Time::now().unwrap();
let now = self.state.now();
for capture in self.screencopies.lock().drain_values() {
let wl_buffer = match capture.buffer.take() {
Some(b) => b,

View file

@ -2,7 +2,7 @@ use {
crate::{
async_engine::{AsyncEngine, SpawnedFuture},
io_uring::{IoUring, IoUringError},
time::{Time, TimeError},
time::Time,
utils::{
buf::TypedBuf, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt,
numcell::NumCell, oserror::OsError, stack::Stack,
@ -28,8 +28,6 @@ pub enum WheelError {
CreateFailed(#[source] OsError),
#[error("Could not set the timerfd")]
SetFailed(#[source] OsError),
#[error("Cannot determine the time")]
TimeError(#[from] TimeError),
#[error("The timer wheel is already destroyed")]
Destroyed,
#[error("Could not read from the timerfd")]
@ -99,6 +97,7 @@ impl Future for WheelTimeoutFuture {
pub struct WheelData {
destroyed: Cell<bool>,
ring: Rc<IoUring>,
eng: Rc<AsyncEngine>,
fd: Rc<OwnedFd>,
next_id: NumCell<u64>,
start: Time,
@ -118,9 +117,10 @@ impl Wheel {
let data = Rc::new(WheelData {
destroyed: Cell::new(false),
ring: ring.clone(),
eng: eng.clone(),
fd,
next_id: NumCell::new(1),
start: Time::now()?,
start: eng.now(),
current_expiration: Default::default(),
dispatchers: Default::default(),
expirations: Default::default(),
@ -161,13 +161,7 @@ impl Wheel {
};
}
let future = self.future();
let now = match Time::now() {
Ok(n) => n,
Err(e) => {
future.data.expired.set(Some(Err(WheelError::TimeError(e))));
return future;
}
};
let now = self.data.eng.now();
let expiration = (now + Duration::from_millis(ms)).round_to_ms();
let current = self.data.current_expiration.get();
if current.is_none() || expiration - self.data.start < current.unwrap() - self.data.start {
@ -224,7 +218,7 @@ impl WheelData {
if let Err(e) = self.ring.read(&self.fd, n.buf()).await {
return Err(WheelError::Read(e));
}
let now = Time::now()?;
let now = self.eng.now();
let dist = now - self.start;
{
let mut expirations = self.expirations.borrow_mut();

View file

@ -23,7 +23,6 @@ use {
io_uring::{IoUring, IoUringError},
rect::Rect,
state::State,
time::Time,
tree::{Node, ToplevelNode},
utils::{
bitflags::BitflagsExt, buf::Buf, cell_ext::CellExt, clonecell::CloneCell,
@ -71,6 +70,7 @@ use {
mem::{self},
ops::{Deref, DerefMut},
rc::Rc,
time::Duration,
},
uapi::{c, OwnedFd},
};
@ -2514,7 +2514,7 @@ struct XToWaylandTransfer {
impl XToWaylandTransfer {
async fn run(mut self) {
let timeout = Time::in_ms(5000).unwrap();
let timeout = self.state.now() + Duration::from_millis(5000);
let mut pos = 0;
while pos < self.data.len() {
let res = self