Skip to content

Commit

Permalink
new private NotcursesInner struct
Browse files Browse the repository at this point in the history
- update `Notcurses`:
  - store `NotcursesInner` wrapping the raw pointer.
  - move proper shutdown functionality to `NotcursesInner`.
- update `Plane`:
  - store a cloned reference to `NotcursesInner`.
  • Loading branch information
joseluis committed Oct 2, 2024
1 parent 864e3da commit fd67fb2
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 30 deletions.
6 changes: 3 additions & 3 deletions src/notcurses/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@

use crate::{
error::NotcursesResult as Result,
notcurses::{LogLevel, Notcurses},
notcurses::{LogLevel, Notcurses, NotcursesInner},
sys::{Nc, NcOptionsBuilder},
};
use std::{cell::RefCell, rc::Rc};

/// A [`Notcurses`] builder.
#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -39,8 +38,9 @@ impl NotcursesBuilder {
pub fn build(self) -> Result<Notcurses> {
Notcurses::lock_notcurses()?;
let nc = unsafe { Nc::with_options(self.options.build())? };

Ok(Notcurses {
nc: Rc::new(RefCell::new(nc)),
inner: NotcursesInner::new(nc),
options: self.options,
})
}
Expand Down
1 change: 1 addition & 0 deletions src/notcurses/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod notcurses;
mod statistics;

pub use self::notcurses::Notcurses;
pub(crate) use self::notcurses::NotcursesInner;
pub use builder::NotcursesBuilder;
pub use capabilities::Capabilities;
pub use log_level::LogLevel;
Expand Down
45 changes: 30 additions & 15 deletions src/notcurses/notcurses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,46 @@ use crate::{
};
use std::{cell::RefCell, rc::Rc};

/// Maintains the notcurses context alive until all dependend objects are dropped.
pub(crate) struct NotcursesInner {
pub(crate) nc: *mut Nc,
}
impl NotcursesInner {
#[inline]
#[must_use]
pub(crate) fn new(nc: *mut Nc) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(NotcursesInner { nc }))
}
}

/// *Notcurses* state for a given terminal, composed of [`Plane`][crate::plane::Plane]s.
///
/// There can only be a single `Notcurses` instance per thread at any given moment.
pub struct Notcurses {
pub(crate) nc: Rc<RefCell<*mut Nc>>,
pub(super) options: NcOptionsBuilder,
// This is cloned in dependent objects, to ensure proper drop order.
pub(crate) inner: Rc<RefCell<NotcursesInner>>,
pub(crate) options: NcOptionsBuilder,
}

mod core_impls {
use super::{Nc, Notcurses, OnceCell, NOTCURSES_LOCK};
use super::{Notcurses, NotcursesInner, OnceCell, NOTCURSES_LOCK};
use core::fmt;

impl Drop for Notcurses {
// Notcurses will be properly stopped after all dependent objects are dropped
impl Drop for NotcursesInner {
fn drop(&mut self) {
// Allows initializing a new Notcurses instance again.
NOTCURSES_LOCK.with(|refcell| {
refcell.replace(OnceCell::new());
});
let nc_ptr: *mut Nc = *self.nc.borrow_mut();
let nc_ptr = self.nc;
if !nc_ptr.is_null() {
unsafe {
(*nc_ptr).drop_planes();
(*nc_ptr).stop().expect("Notcurses.stop() failed");
}
}

// Unlock the static lock to allow new `Notcurses` instances
NOTCURSES_LOCK.with(|refcell| {
refcell.replace(OnceCell::new());
});
}
}

Expand Down Expand Up @@ -146,7 +161,7 @@ impl Notcurses {
let options = NcOptionsBuilder::new().suppress_banners(true);
let nc_ptr = unsafe { Nc::with_options(options.build())? };
Ok(Notcurses {
nc: Rc::new(RefCell::new(nc_ptr)),
inner: NotcursesInner::new(nc_ptr),
options,
})
}
Expand All @@ -157,7 +172,7 @@ impl Notcurses {
let options = NcOptionsBuilder::new();
let nc_ptr = unsafe { Nc::with_options(options.build())? };
Ok(Notcurses {
nc: Rc::new(RefCell::new(nc_ptr)),
inner: NotcursesInner::new(nc_ptr),
options,
})
}
Expand All @@ -170,7 +185,7 @@ impl Notcurses {
.cli_mode(true);
let nc_ptr = unsafe { Nc::with_options(options.build())? };
Ok(Notcurses {
nc: Rc::new(RefCell::new(nc_ptr)),
inner: NotcursesInner::new(nc_ptr),
options,
})
}
Expand All @@ -181,7 +196,7 @@ impl Notcurses {
let options = NcOptionsBuilder::new().cli_mode(true);
let nc_ptr = unsafe { Nc::with_options(options.build())? };
Ok(Notcurses {
nc: Rc::new(RefCell::new(nc_ptr)),
inner: NotcursesInner::new(nc_ptr),
options,
})
}
Expand All @@ -194,7 +209,7 @@ impl Notcurses {
where
F: FnOnce(&Nc) -> R,
{
let nc_ptr = *self.nc.borrow();
let nc_ptr = self.inner.borrow().nc;
unsafe { f(&*nc_ptr) }
}

Expand All @@ -204,7 +219,7 @@ impl Notcurses {
where
F: FnOnce(&mut Nc) -> R,
{
let nc_ptr = *self.nc.borrow_mut();
let nc_ptr = self.inner.borrow_mut().nc;
unsafe { f(&mut *nc_ptr) }
}
}
Expand Down
9 changes: 4 additions & 5 deletions src/plane/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::{
sys::{Nc, NcPlane, NcPlaneOptionsBuilder},
Notcurses, Position, Size,
};
use std::{cell::RefMut, rc::Rc};

/// A [`Plane`] builder.
#[derive(Debug, Default)]
Expand All @@ -29,15 +28,15 @@ impl PlaneBuilder {

/// Returns a new standalone `Plane`.
pub fn build(self, nc: &Notcurses) -> Result<Plane> {
let notcurses = Rc::clone(&nc.nc);
let notcurses = nc.inner.clone();
let ncplane = {
let nc_borrow: RefMut<*mut Nc> = notcurses.borrow_mut();
let nc_ptr: *mut Nc = *nc_borrow;
let inner_nc = notcurses.borrow_mut();
let nc_ptr: *mut Nc = inner_nc.nc;

// SAFETY: ensured via RefCell's borrowing rules
let nc_ref: &mut Nc = unsafe { &mut *nc_ptr };
NcPlane::new_pile(nc_ref, &self.options.build())?
};

Ok(Plane {
nc: ncplane,
notcurses,
Expand Down
14 changes: 7 additions & 7 deletions src/plane/plane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
use crate::{
color::{Channel, Channels},
error::NotcursesResult as Result,
notcurses::{Capabilities, Notcurses},
notcurses::{Capabilities, Notcurses, NotcursesInner},
plane::{Align, Cell, PlaneBuilder, PlaneGeometry, Style},
sys::{Nc, NcPlane},
sys::NcPlane,
visual::Blitter,
Position, Size,
};
Expand All @@ -17,7 +17,8 @@ use std::{cell::RefCell, rc::Rc};
/// A drawable text surface, composed of [`Cell`]s.
pub struct Plane {
pub(super) nc: *mut NcPlane,
pub(super) notcurses: Rc<RefCell<*mut Nc>>,
// Ensures the notcurses context remains alive as long as this object exists
pub(super) notcurses: Rc<RefCell<NotcursesInner>>,
}

mod core_impls {
Expand All @@ -34,8 +35,7 @@ mod core_impls {
CLI_PLANE_LOCK.with(|refcell| {
refcell.replace(OnceCell::new());
});
} else if crate::Notcurses::is_initialized() && self.notcurses.try_borrow_mut().is_ok()
{
} else if crate::Notcurses::is_initialized() {
let _res = self.into_ref_mut().destroy();
}
}
Expand Down Expand Up @@ -89,7 +89,7 @@ impl Plane {
pub fn from_ncplane(ncplane: &mut NcPlane, notcurses: &Notcurses) -> Plane {
Plane {
nc: ncplane as *mut NcPlane,
notcurses: notcurses.nc.clone(),
notcurses: notcurses.inner.clone(),
}
}

Expand Down Expand Up @@ -198,7 +198,7 @@ impl Plane {
pub fn duplicate(&self) -> Plane {
Plane {
nc: self.into_ref().dup(),
notcurses: Rc::clone(&self.notcurses),
notcurses: self.notcurses.clone(),
}
}

Expand Down

0 comments on commit fd67fb2

Please sign in to comment.