pub(crate) mod util;
pub mod design;
mod error;
pub mod logical;
pub mod physical;
mod traits;
#[cfg(feature = "generator")]
pub mod generator;
#[cfg(feature = "parser")]
pub mod parser;
pub use error::{Error, Result};
pub use traits::{Reverse, Reversed};
pub use util::{Logger, UniquelyNamedBuilder};
pub type Positive = std::num::NonZeroU32;
pub type NonNegative = u32;
pub type PositiveReal = NonZeroReal<f64>;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NonZeroReal<T>(T);
impl<T> NonZeroReal<T>
where
T: Copy + Into<f64>,
{
pub fn new(real: T) -> Result<Self> {
if real.into() > 0. {
Ok(NonZeroReal(real))
} else {
Err(Error::InvalidArgument("real must be positive".to_string()))
}
}
}
use std::ops::Mul;
impl<T> Mul for NonZeroReal<T>
where
T: Copy + Mul<Output = T> + Into<f64>,
{
type Output = NonZeroReal<T>;
fn mul(self, other: NonZeroReal<T>) -> Self::Output {
NonZeroReal::new(self.0 * other.0).unwrap()
}
}
impl<T> NonZeroReal<T>
where
T: Copy,
{
pub fn get(&self) -> T {
self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Name(String);
impl Name {
pub fn try_new(name: impl Into<String>) -> Result<Self> {
let name = name.into();
if name.is_empty() {
Err(Error::InvalidArgument("name cannot be empty".to_string()))
} else if name.chars().next().unwrap().is_ascii_digit() {
Err(Error::InvalidArgument(
"name cannot start with a digit".to_string(),
))
} else if name.starts_with('_') || name.ends_with('_') {
Err(Error::InvalidArgument(
"name cannot start or end with an underscore".to_string(),
))
} else if name.contains("__") {
Err(Error::InvalidArgument(
"name cannot contain two or more consecutive underscores".to_string(),
))
} else if !name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c.eq(&'_'))
{
Err(Error::InvalidArgument(
"name must consist of letters, numbers, and/or underscores".to_string(),
))
} else {
Ok(Name(name))
}
}
}
impl From<Name> for String {
fn from(name: Name) -> Self {
name.0
}
}
impl From<&Name> for String {
fn from(name: &Name) -> Self {
name.0.clone()
}
}
use std::ops::Deref;
impl Deref for Name {
type Target = str;
fn deref(&self) -> &str {
self.0.as_ref()
}
}
use std::convert::TryFrom;
impl TryFrom<&str> for Name {
type Error = Error;
fn try_from(str: &str) -> Result<Self> {
Name::try_new(str)
}
}
impl TryFrom<String> for Name {
type Error = Error;
fn try_from(string: String) -> Result<Self> {
Name::try_new(string)
}
}
use std::str::FromStr;
impl FromStr for Name {
type Err = Error;
fn from_str(str: &str) -> Result<Self> {
Name::try_new(str)
}
}
impl PartialEq<String> for Name {
fn eq(&self, other: &String) -> bool {
&self.0 == other
}
}
impl PartialEq<str> for Name {
fn eq(&self, other: &str) -> bool {
self.0 == other
}
}
use std::fmt;
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PathName(Vec<Name>);
use std::convert::TryInto;
impl PathName {
pub(crate) fn new_empty() -> Self {
PathName(Vec::new())
}
pub fn new(names: impl Iterator<Item = Name>) -> Self {
PathName(names.collect())
}
pub fn try_new(
names: impl IntoIterator<Item = impl TryInto<Name, Error = Error>>,
) -> Result<Self> {
Ok(PathName(
names
.into_iter()
.map(|name| name.try_into())
.collect::<Result<_>>()?,
))
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn push(&mut self, name: impl Into<Name>) {
self.0.push(name.into())
}
pub(crate) fn with_parent(&self, name: impl Into<Name>) -> PathName {
let mut result: Vec<Name> = Vec::with_capacity(self.len() + 1);
result.push(name.into());
let mut names = self.0.clone().into_iter();
result.extend(&mut names);
PathName::new(result.into_iter())
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn last(&self) -> Option<&Name> {
self.0.last()
}
pub fn parent(&self) -> Option<PathName> {
if self.is_empty() {
None
} else {
Some(PathName(self.0[..self.len() - 1].to_vec()))
}
}
}
impl fmt::Display for PathName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut result = String::new();
let mut names = self.0.iter().map(|x| x.as_ref());
if let Some(x) = names.next() {
result.push_str(&x);
names.for_each(|name| {
result.push_str("__");
result.push_str(name);
});
} else {
result.push_str("");
}
write!(f, "{}", result)
}
}
impl<'a> IntoIterator for &'a PathName {
type Item = &'a Name;
type IntoIter = std::slice::Iter<'a, Name>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
use std::iter::FromIterator;
impl FromIterator<Name> for PathName {
fn from_iter<I: IntoIterator<Item = Name>>(iter: I) -> Self {
PathName(iter.into_iter().collect())
}
}
impl From<Name> for PathName {
fn from(name: Name) -> Self {
PathName(vec![name])
}
}
impl TryFrom<String> for PathName {
type Error = Error;
fn try_from(string: String) -> Result<Self> {
let name: Name = string.try_into()?;
Ok(PathName::from(name))
}
}
impl TryFrom<&str> for PathName {
type Error = Error;
fn try_from(str: &str) -> Result<Self> {
let name: Name = str.try_into()?;
Ok(PathName::from(name))
}
}