mod block_comment;
mod comment;
use core::fmt::Write as _;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::string::{String, ToString};
use crate as genco;
use crate::fmt;
use crate::quote_in;
use crate::tokens::ItemStr;
pub use self::block_comment::BlockComment;
pub use self::comment::Comment;
pub type Tokens = crate::Tokens<Csharp>;
impl_lang! {
pub Csharp {
type Config = Config;
type Format = Format;
type Item = Import;
fn write_quoted(out: &mut fmt::Formatter<'_>, input: &str) -> fmt::Result {
super::c_family_write_quoted(out, input)
}
fn format_file(
tokens: &Tokens,
out: &mut fmt::Formatter<'_>,
config: &Self::Config,
) -> fmt::Result {
let mut file: Tokens = Tokens::new();
let mut format = Format::default();
Self::imports(&mut file, tokens, config, &mut format.imported_names);
if let Some(namespace) = &config.namespace {
quote_in! { file =>
namespace $namespace {
$tokens
}
}
file.format(out, config, &format)?;
} else {
file.format(out, config, &format)?;
tokens.format(out, config, &format)?;
}
Ok(())
}
}
Import(Import) {
fn format(&self, out: &mut fmt::Formatter<'_>, config: &Config, format: &Format) -> fmt::Result {
{
let qualified = self.qualified || is_qualified(config, format, &self.namespace, &self.name);
if qualified {
out.write_str(&self.namespace)?;
out.write_str(SEP)?;
}
}
out.write_str(&self.name)?;
return Ok(());
fn is_qualified(config: &Config, format: &Format, namespace: &str, name: &str) -> bool {
if let Some(config) = &config.namespace {
if &**config == namespace {
return false;
}
}
if let Some(imported) = format.imported_names.get(name) {
if imported != namespace {
return true;
}
}
false
}
}
}
}
const SEP: &str = ".";
#[derive(Debug, Default)]
pub struct Format {
imported_names: BTreeMap<String, String>,
}
#[derive(Debug, Default)]
pub struct Config {
namespace: Option<ItemStr>,
}
impl Config {
pub fn with_namespace<N>(self, namespace: N) -> Self
where
N: Into<ItemStr>,
{
Self {
namespace: Some(namespace.into()),
}
}
}
#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Import {
namespace: ItemStr,
name: ItemStr,
qualified: bool,
}
impl Import {
pub fn qualified(self) -> Self {
Self {
qualified: true,
..self
}
}
}
impl Csharp {
fn imports(
out: &mut Tokens,
tokens: &Tokens,
config: &Config,
imported_names: &mut BTreeMap<String, String>,
) {
let mut modules = BTreeSet::new();
for import in tokens.iter_lang() {
modules.insert((&*import.namespace, &*import.name));
}
if modules.is_empty() {
return;
}
let mut imported = BTreeSet::new();
for (namespace, name) in modules {
if Some(namespace) == config.namespace.as_deref() {
continue;
}
match imported_names.get(name) {
Some(existing) if existing == namespace => continue,
Some(_) => continue,
_ => {}
}
if !imported.contains(namespace) {
quote_in!(*out => using $namespace;);
out.push();
imported.insert(namespace);
}
imported_names.insert(name.to_string(), namespace.to_string());
}
out.line();
}
}
pub fn import<P, N>(namespace: P, name: N) -> Import
where
P: Into<ItemStr>,
N: Into<ItemStr>,
{
Import {
namespace: namespace.into(),
name: name.into(),
qualified: false,
}
}
pub fn block_comment<T>(comment: T) -> BlockComment<T>
where
T: IntoIterator,
T::Item: Into<ItemStr>,
{
BlockComment(comment)
}
pub fn comment<T>(comment: T) -> Comment<T>
where
T: IntoIterator,
T::Item: Into<ItemStr>,
{
Comment(comment)
}