use std::ops::{Deref, Index};
use std::{fmt, iter, slice};
use crate::core_ext::*;
use proc_macro2::{Ident, TokenStream};
use quote::{ToTokens, TokenStreamExt};
use syn::Token;
pub const OPTION: ModulePrefix<'static> = ModulePrefix::new(&["core", "option", "Option"]);
pub const RESULT: ModulePrefix<'static> = ModulePrefix::new(&["core", "result", "Result"]);
#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
#[cfg(feature = "module-prefix")]
pub struct ModulePrefix<'a> {
path: &'a [&'a str],
leading_sep: bool,
}
#[cfg(feature = "module-prefix")]
pub struct Chain<A, B> {
a: A,
b: B,
}
impl<'a> ModulePrefix<'a> {
#[inline]
#[must_use]
pub const fn new(segments: &'a [&'a str]) -> Self {
Self {
path: segments,
leading_sep: true,
}
}
#[inline]
#[must_use]
pub const fn with_leading_sep(mut self, leading_sep: bool) -> Self {
self.leading_sep = leading_sep;
self
}
}
impl<'a> IntoIterator for ModulePrefix<'a> {
type Item = &'a str;
type IntoIter = iter::Copied<slice::Iter<'a, &'a str>>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.path.iter().copied()
}
}
impl ToTokens for ModulePrefix<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut iter = self.into_iter();
if !self.leading_sep {
if let Some(first) = iter.next() {
tokens.append(Ident::create(first));
} else {
return;
}
}
let sep = <Token![::]>::default();
for segment in iter {
sep.to_tokens(tokens);
tokens.append(Ident::create(segment));
}
}
}
impl fmt::Display for ModulePrefix<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut iter = self.into_iter();
let Some(first) = iter.next() else {
return Ok(());
};
if self.leading_sep {
f.write_str(":: ")?;
f.write_str(first)?;
} else {
f.write_str(first)?;
}
for item in iter {
f.write_str(" :: ")?;
f.write_str(item)?;
}
Ok(())
}
}
impl<'a> Deref for ModulePrefix<'a> {
type Target = [&'a str];
#[inline]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<'a> AsRef<[&'a str]> for ModulePrefix<'a> {
#[inline]
fn as_ref(&self) -> &[&'a str] {
self.path
}
}
impl Index<usize> for ModulePrefix<'_> {
type Output = str;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
self.path[index]
}
}
impl ModulePrefix<'_> {
#[cfg_attr(doctest, doc = " ````no_test")]
pub const fn chain<T>(self, next_segment: T) -> Chain<Self, T>
where
T: ToTokens,
{
Chain {
a: self,
b: next_segment,
}
}
}
impl<A, B> Chain<A, B> {
pub const fn chain<C>(self, next_segment: C) -> Chain<Self, C>
where
C: ToTokens,
{
Chain {
a: self,
b: next_segment,
}
}
}
impl<A: ToTokens, B: ToTokens> ToTokens for Chain<A, B> {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.a.to_tokens(tokens);
<Token![::]>::default().to_tokens(tokens);
self.b.to_tokens(tokens);
}
}