use std::fmt::{Display, Formatter, Write};
use anyhow::Context;
use bimap::BiHashMap;
use guppy::PackageId;
use crate::render::{LifetimeStyle, PathStyle, RenderConfig};
use crate::{GenericArgument, Type};
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct FreeFunctionPath {
pub package_id: PackageId,
pub crate_name: String,
pub module_path: Vec<String>,
pub function_name: String,
pub function_generics: Vec<GenericArgument>,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct InherentMethodPath {
pub package_id: PackageId,
pub crate_name: String,
pub module_path: Vec<String>,
pub type_name: String,
pub type_generics: Vec<GenericArgument>,
pub method_name: String,
pub method_generics: Vec<GenericArgument>,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct TraitMethodPath {
pub package_id: PackageId,
pub crate_name: String,
pub module_path: Vec<String>,
pub trait_name: String,
pub trait_generics: Vec<GenericArgument>,
pub self_type: Type,
pub method_name: String,
pub method_generics: Vec<GenericArgument>,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct StructLiteralPath {
pub package_id: PackageId,
pub crate_name: String,
pub module_path: Vec<String>,
pub type_name: String,
pub type_generics: Vec<GenericArgument>,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct EnumVariantConstructorPath {
pub package_id: PackageId,
pub crate_name: String,
pub module_path: Vec<String>,
pub enum_name: String,
pub enum_generics: Vec<GenericArgument>,
pub variant_name: String,
}
fn render_generics<W: Write>(
generics: &[GenericArgument],
config: &RenderConfig<'_>,
buffer: &mut W,
) {
if !generics.is_empty() {
write!(buffer, "::<").unwrap();
let mut args = generics.iter().peekable();
while let Some(arg) = args.next() {
arg.render_into(config, buffer);
if args.peek().is_some() {
write!(buffer, ", ").unwrap();
}
}
write!(buffer, ">").unwrap();
}
}
impl FreeFunctionPath {
pub fn render_path(&self, id2name: &BiHashMap<PackageId, String>, buffer: &mut String) {
let crate_name = id2name
.get_by_left(&self.package_id)
.with_context(|| {
format!(
"The package id '{}' is missing from the id<>name mapping for crates.",
self.package_id
)
})
.unwrap();
let config = RenderConfig {
path: PathStyle::CrateLookup(id2name),
lifetime: LifetimeStyle::Erase,
};
write!(buffer, "{crate_name}").unwrap();
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.function_name).unwrap();
render_generics(&self.function_generics, &config, buffer);
}
pub fn render_for_error(&self, buffer: &mut String) {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
buffer.push_str(&self.crate_name);
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.function_name).unwrap();
render_generics(&self.function_generics, &config, buffer);
}
}
impl Display for FreeFunctionPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
write!(f, "{}", self.crate_name)?;
for module in &self.module_path {
write!(f, "::{module}")?;
}
write!(f, "::{}", self.function_name)?;
render_generics(&self.function_generics, &config, f);
Ok(())
}
}
impl InherentMethodPath {
pub fn render_path(&self, id2name: &BiHashMap<PackageId, String>, buffer: &mut String) {
let crate_name = id2name
.get_by_left(&self.package_id)
.with_context(|| {
format!(
"The package id '{}' is missing from the id<>name mapping for crates.",
self.package_id
)
})
.unwrap();
let config = RenderConfig {
path: PathStyle::CrateLookup(id2name),
lifetime: LifetimeStyle::Erase,
};
write!(buffer, "{crate_name}").unwrap();
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.type_name).unwrap();
render_generics(&self.type_generics, &config, buffer);
write!(buffer, "::{}", self.method_name).unwrap();
render_generics(&self.method_generics, &config, buffer);
}
pub fn render_for_error(&self, buffer: &mut String) {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
buffer.push_str(&self.crate_name);
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.type_name).unwrap();
render_generics(&self.type_generics, &config, buffer);
write!(buffer, "::{}", self.method_name).unwrap();
render_generics(&self.method_generics, &config, buffer);
}
}
impl Display for InherentMethodPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
write!(f, "{}", self.crate_name)?;
for module in &self.module_path {
write!(f, "::{module}")?;
}
write!(f, "::{}", self.type_name)?;
render_generics(&self.type_generics, &config, f);
write!(f, "::{}", self.method_name)?;
render_generics(&self.method_generics, &config, f);
Ok(())
}
}
impl TraitMethodPath {
pub fn render_path(&self, id2name: &BiHashMap<PackageId, String>, buffer: &mut String) {
let crate_name = id2name
.get_by_left(&self.package_id)
.with_context(|| {
format!(
"The package id '{}' is missing from the id<>name mapping for crates.",
self.package_id
)
})
.unwrap();
let config = RenderConfig {
path: PathStyle::CrateLookup(id2name),
lifetime: LifetimeStyle::Erase,
};
write!(buffer, "<").unwrap();
self.self_type.render_into(&config, buffer);
write!(buffer, " as {crate_name}").unwrap();
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.trait_name).unwrap();
render_generics(&self.trait_generics, &config, buffer);
write!(buffer, ">").unwrap();
write!(buffer, "::{}", self.method_name).unwrap();
render_generics(&self.method_generics, &config, buffer);
}
pub fn render_for_error(&self, buffer: &mut String) {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
write!(buffer, "<").unwrap();
self.self_type.render_into(&config, buffer);
write!(buffer, " as {}", self.crate_name).unwrap();
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.trait_name).unwrap();
render_generics(&self.trait_generics, &config, buffer);
write!(buffer, ">").unwrap();
write!(buffer, "::{}", self.method_name).unwrap();
render_generics(&self.method_generics, &config, buffer);
}
}
impl Display for TraitMethodPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
write!(f, "<")?;
self.self_type.render_into(&config, f);
write!(f, " as {}", self.crate_name)?;
for module in &self.module_path {
write!(f, "::{module}")?;
}
write!(f, "::{}", self.trait_name)?;
render_generics(&self.trait_generics, &config, f);
write!(f, ">")?;
write!(f, "::{}", self.method_name)?;
render_generics(&self.method_generics, &config, f);
Ok(())
}
}
impl StructLiteralPath {
pub fn render_path(&self, id2name: &BiHashMap<PackageId, String>, buffer: &mut String) {
let crate_name = id2name
.get_by_left(&self.package_id)
.with_context(|| {
format!(
"The package id '{}' is missing from the id<>name mapping for crates.",
self.package_id
)
})
.unwrap();
let config = RenderConfig {
path: PathStyle::CrateLookup(id2name),
lifetime: LifetimeStyle::Erase,
};
write!(buffer, "{crate_name}").unwrap();
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.type_name).unwrap();
render_generics(&self.type_generics, &config, buffer);
}
pub fn render_for_error(&self, buffer: &mut String) {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
buffer.push_str(&self.crate_name);
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.type_name).unwrap();
render_generics(&self.type_generics, &config, buffer);
}
}
impl Display for StructLiteralPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
write!(f, "{}", self.crate_name)?;
for module in &self.module_path {
write!(f, "::{module}")?;
}
write!(f, "::{}", self.type_name)?;
render_generics(&self.type_generics, &config, f);
Ok(())
}
}
impl EnumVariantConstructorPath {
pub fn render_path(&self, id2name: &BiHashMap<PackageId, String>, buffer: &mut String) {
let crate_name = id2name
.get_by_left(&self.package_id)
.with_context(|| {
format!(
"The package id '{}' is missing from the id<>name mapping for crates.",
self.package_id
)
})
.unwrap();
let config = RenderConfig {
path: PathStyle::CrateLookup(id2name),
lifetime: LifetimeStyle::Erase,
};
write!(buffer, "{crate_name}").unwrap();
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.enum_name).unwrap();
render_generics(&self.enum_generics, &config, buffer);
write!(buffer, "::{}", self.variant_name).unwrap();
}
pub fn render_for_error(&self, buffer: &mut String) {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
buffer.push_str(&self.crate_name);
for module in &self.module_path {
write!(buffer, "::{module}").unwrap();
}
write!(buffer, "::{}", self.enum_name).unwrap();
render_generics(&self.enum_generics, &config, buffer);
write!(buffer, "::{}", self.variant_name).unwrap();
}
}
impl Display for EnumVariantConstructorPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let config = RenderConfig {
path: PathStyle::Direct,
lifetime: LifetimeStyle::Preserve,
};
write!(f, "{}", self.crate_name)?;
for module in &self.module_path {
write!(f, "::{module}")?;
}
write!(f, "::{}", self.enum_name)?;
render_generics(&self.enum_generics, &config, f);
write!(f, "::{}", self.variant_name)
}
}