use std::fs::File;
use std::io;
use super::{os, Role};
#[derive(Default)]
pub(super) struct GuardedLedger {
#[cfg(unix)]
entries: Vec<GuardedIdentity>,
#[cfg(windows)]
entries: Vec<(os::Identity, Role)>,
}
impl GuardedLedger {
pub(super) fn contains_identity(&self, identity: os::Identity) -> bool {
#[cfg(unix)]
{
self.entries.iter().any(|entry| entry.identity == identity)
}
#[cfg(windows)]
{
self.entries.iter().any(|(opened, _)| *opened == identity)
}
}
pub(super) fn has_other_role(&self, identity: os::Identity, role: Role) -> bool {
#[cfg(unix)]
{
self.entries
.iter()
.any(|entry| entry.identity == identity && entry.role != role)
}
#[cfg(windows)]
{
self.entries
.iter()
.any(|(opened, opened_role)| *opened == identity && *opened_role != role)
}
}
pub(super) fn record(
&mut self,
file: &File,
identity: os::Identity,
role: Role,
) -> io::Result<()> {
#[cfg(unix)]
{
if let Some(entry) = self
.entries
.iter_mut()
.find(|entry| entry.identity == identity && entry.role == role)
{
entry.open_handles += 1;
} else {
self.entries.push(GuardedIdentity {
identity,
role,
open_handles: 1,
anchor: Some(file.try_clone()?),
});
}
}
#[cfg(windows)]
{
let _ = file;
self.entries.push((identity, role));
}
Ok(())
}
pub(super) fn release(&mut self, identity: os::Identity, role: Role) {
#[cfg(unix)]
if let Some(entry) = self
.entries
.iter_mut()
.find(|entry| entry.identity == identity && entry.role == role)
{
entry.open_handles = entry.open_handles.saturating_sub(1);
}
#[cfg(windows)]
let _ = (identity, role);
}
pub(super) fn retire_unlinked(&mut self) {
#[cfg(unix)]
self.entries.retain(|entry| !entry.can_retire());
}
#[cfg(all(test, unix))]
pub(super) fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[cfg(unix)]
struct GuardedIdentity {
identity: os::Identity,
role: Role,
open_handles: usize,
anchor: Option<File>,
}
#[cfg(unix)]
impl GuardedIdentity {
fn can_retire(&self) -> bool {
self.open_handles == 0
&& os::is_unlinked(self.anchor.as_ref().expect("ledger anchor remains open"))
.unwrap_or(false)
}
}
#[cfg(unix)]
impl Drop for GuardedIdentity {
fn drop(&mut self) {
if let Some(anchor) = self.anchor.take() {
os::close_unlocked(anchor, self.identity);
}
}
}