use std::error::Error;
use std::fmt;
use std::ops::Deref;
use std::sync::Arc;
use crate::configuration::{AccessMode, ParseConfiguration};
use crate::link_network::LinkNetwork;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ReadOnlyViolation;
impl fmt::Display for ReadOnlyViolation {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(
"engine is configured read-only; mutation is rejected. \
Re-parse with AccessMode::Mutable or fork an editable copy via \
ReadOnlyNetwork::to_mutable before mutating.",
)
}
}
impl Error for ReadOnlyViolation {}
#[derive(Clone, Debug)]
pub struct ReadOnlyNetwork {
network: Arc<LinkNetwork>,
}
impl ReadOnlyNetwork {
#[must_use]
pub fn new(network: LinkNetwork) -> Self {
Self {
network: Arc::new(network),
}
}
#[must_use]
pub const fn from_shared(network: Arc<LinkNetwork>) -> Self {
Self { network }
}
#[must_use]
pub fn network(&self) -> &LinkNetwork {
&self.network
}
#[must_use]
pub const fn shared(&self) -> &Arc<LinkNetwork> {
&self.network
}
#[must_use]
pub fn into_shared(self) -> Arc<LinkNetwork> {
self.network
}
#[must_use]
pub fn shared_count(&self) -> usize {
Arc::strong_count(&self.network)
}
#[must_use]
pub fn to_mutable(&self) -> LinkNetwork {
self.network.as_ref().clone()
}
#[must_use]
pub fn into_mutable(self) -> LinkNetwork {
Arc::try_unwrap(self.network).unwrap_or_else(|shared| shared.as_ref().clone())
}
}
impl Deref for ReadOnlyNetwork {
type Target = LinkNetwork;
fn deref(&self) -> &Self::Target {
&self.network
}
}
impl PartialEq for ReadOnlyNetwork {
fn eq(&self, other: &Self) -> bool {
self.network == other.network
}
}
impl Eq for ReadOnlyNetwork {}
impl From<LinkNetwork> for ReadOnlyNetwork {
fn from(network: LinkNetwork) -> Self {
Self::new(network)
}
}
impl LinkNetwork {
#[must_use]
pub fn freeze(self) -> ReadOnlyNetwork {
ReadOnlyNetwork::new(self)
}
#[must_use]
pub fn as_read_only(&self) -> ReadOnlyNetwork {
ReadOnlyNetwork::new(self.clone())
}
#[must_use]
pub fn parse_engine(
text: &str,
language: &str,
configuration: ParseConfiguration,
) -> EngineNetwork {
let network = Self::parse(text, language, configuration);
EngineNetwork::with_access_mode(network, configuration.access_mode())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EngineNetwork {
Mutable(LinkNetwork),
ReadOnly(ReadOnlyNetwork),
}
impl EngineNetwork {
#[must_use]
pub fn with_access_mode(network: LinkNetwork, access_mode: AccessMode) -> Self {
match access_mode {
AccessMode::Mutable => Self::Mutable(network),
AccessMode::ReadOnly => Self::ReadOnly(network.freeze()),
}
}
#[must_use]
pub const fn access_mode(&self) -> AccessMode {
match self {
Self::Mutable(_) => AccessMode::Mutable,
Self::ReadOnly(_) => AccessMode::ReadOnly,
}
}
#[must_use]
pub const fn is_mutable(&self) -> bool {
matches!(self, Self::Mutable(_))
}
#[must_use]
pub const fn is_read_only(&self) -> bool {
matches!(self, Self::ReadOnly(_))
}
#[must_use]
pub fn network(&self) -> &LinkNetwork {
match self {
Self::Mutable(network) => network,
Self::ReadOnly(view) => view.network(),
}
}
pub fn as_mutable(&mut self) -> Result<&mut LinkNetwork, ReadOnlyViolation> {
match self {
Self::Mutable(network) => Ok(network),
Self::ReadOnly(_) => Err(ReadOnlyViolation),
}
}
#[must_use]
pub fn into_read_only(self) -> ReadOnlyNetwork {
match self {
Self::Mutable(network) => network.freeze(),
Self::ReadOnly(view) => view,
}
}
#[must_use]
pub fn into_mutable(self) -> LinkNetwork {
match self {
Self::Mutable(network) => network,
Self::ReadOnly(view) => view.into_mutable(),
}
}
}
impl Deref for EngineNetwork {
type Target = LinkNetwork;
fn deref(&self) -> &Self::Target {
self.network()
}
}