use std::fmt::Display;
use std::mem::take;
use std::sync::atomic::Ordering;
use std::sync::{atomic::AtomicUsize, Arc};
use super::Name;
#[must_use]
#[derive(Debug, Clone)]
pub struct NameBuilder {
id: Arc<AtomicUsize>,
my_id: Option<usize>,
with_id: bool,
generated: bool,
name: Option<String>,
extension: Option<String>,
}
impl NameBuilder {
pub fn new(id: Arc<AtomicUsize>) -> Self {
Self {
id,
my_id: None,
with_id: true,
generated: false,
name: None,
extension: None,
}
}
#[must_use]
pub fn finish(self) -> Name {
let Self {
id,
my_id,
with_id,
mut generated,
name,
extension,
} = self;
let mut ret = String::new();
if let Some(s) = extension {
generated = true;
ret.push_str(&Name::unify(&s));
}
if let Some(s) = name {
if ret.is_empty() {
ret.push_str(&s);
} else {
ret.push_str(&Name::unify(&s));
}
}
if ret.is_empty() {
generated = true;
ret.push_str("Unnamed");
}
if with_id {
generated = true;
let id = my_id.unwrap_or_else(|| id.fetch_add(1, Ordering::Relaxed));
ret = format!("{ret}{id}");
}
if generated {
Name::new_generated(ret)
} else {
Name::new_named(ret)
}
}
pub fn with_id(mut self, value: bool) -> Self {
self.with_id = value;
self
}
pub fn generate_id(mut self) -> Self {
if self.my_id.is_none() {
self.my_id = Some(self.id.fetch_add(1, Ordering::Release));
}
self
}
pub fn unique_name<T>(mut self, value: T) -> Self
where
T: Display,
{
self.name = Some(value.to_string());
self.with_id = false;
self
}
pub fn shared_name<T>(mut self, value: T) -> Self
where
T: Display,
{
self.name = Some(value.to_string());
self.with_id = true;
self
}
pub fn or<T>(self, fallback: T) -> Self
where
T: NameFallback,
{
self.or_else(|| fallback)
}
pub fn or_else<F, T>(mut self, fallback: F) -> Self
where
F: FnOnce() -> T,
T: NameFallback,
{
if self.name.is_none() {
if let Some((generated, name)) = fallback().resolve() {
self.name = Some(name);
self.with_id = false;
self.generated = generated;
}
}
self
}
pub fn extend<I>(mut self, mut replace: bool, iter: I) -> Self
where
I: IntoIterator,
I::Item: Display,
{
for s in iter {
let s = s.to_string();
let s = Name::unify(&s);
if take(&mut replace) {
self.extension = Some(s);
} else if let Some(prefix) = &self.extension {
self.extension = Some(format!("{s}{prefix}"));
} else {
self.extension = Some(s);
}
}
self
}
pub fn remove_suffix(mut self, suffix: &str) -> Self {
if let Some(s) = &mut self.name {
if let Some(x) = s.strip_suffix(suffix) {
*s = x.into();
}
}
if let Some(s) = &mut self.extension {
if let Some(x) = s.strip_suffix(suffix) {
*s = x.into();
}
}
self
}
#[inline]
#[must_use]
pub fn has_extension(&self) -> bool {
self.extension.is_some()
}
}
pub trait NameFallback {
fn resolve(self) -> Option<(bool, String)>;
}
impl NameFallback for Name {
#[inline]
fn resolve(self) -> Option<(bool, String)> {
(&self).resolve()
}
}
impl NameFallback for &Name {
#[inline]
fn resolve(self) -> Option<(bool, String)> {
Some((self.is_generated(), self.as_str().to_owned()))
}
}
impl NameFallback for Option<&Name> {
#[inline]
fn resolve(self) -> Option<(bool, String)> {
self.and_then(NameFallback::resolve)
}
}
impl NameFallback for Option<Name> {
#[inline]
fn resolve(self) -> Option<(bool, String)> {
self.as_ref().resolve()
}
}
impl NameFallback for &Option<Name> {
fn resolve(self) -> Option<(bool, String)> {
self.as_ref().resolve()
}
}
impl NameFallback for &String {
fn resolve(self) -> Option<(bool, String)> {
Some((false, self.to_owned()))
}
}
impl NameFallback for Option<&String> {
fn resolve(self) -> Option<(bool, String)> {
self.and_then(NameFallback::resolve)
}
}
impl NameFallback for Option<String> {
fn resolve(self) -> Option<(bool, String)> {
self.as_ref().resolve()
}
}
impl NameFallback for &Option<String> {
fn resolve(self) -> Option<(bool, String)> {
self.as_ref().resolve()
}
}
impl NameFallback for &str {
fn resolve(self) -> Option<(bool, String)> {
Some((false, self.to_owned()))
}
}
impl NameFallback for Option<&str> {
fn resolve(self) -> Option<(bool, String)> {
self.and_then(NameFallback::resolve)
}
}