use crate::{
ast::{generic::GenericArgs, ty::TyKind},
common::{GenericId, ItemId, VarId, VariantId},
ffi::{FfiOption, FfiSlice},
span::Ident,
};
#[repr(C)]
#[derive(Debug)]
pub struct AstQPath<'ast> {
self_ty: FfiOption<TyKind<'ast>>,
path_ty: FfiOption<TyKind<'ast>>,
path: AstPath<'ast>,
target: AstPathTarget,
}
impl<'ast> AstQPath<'ast> {
pub fn self_ty(&self) -> Option<TyKind<'ast>> {
self.self_ty.copy()
}
pub fn path_ty(&self) -> Option<TyKind<'ast>> {
self.path_ty.copy()
}
pub fn as_path_lossy(&self) -> &AstPath<'ast> {
&self.path
}
pub fn segments(&self) -> &[AstPathSegment<'ast>] {
self.path.segments()
}
pub fn resolve(&self) -> AstPathTarget {
self.target
}
pub fn generics(&self) -> &GenericArgs<'ast> {
self.path.generics()
}
}
impl<'a, 'ast> TryFrom<&'a AstQPath<'ast>> for &'a AstPath<'ast> {
type Error = ();
fn try_from(value: &'a AstQPath<'ast>) -> Result<Self, Self::Error> {
fn is_segment_representable(ty: Option<TyKind<'_>>) -> bool {
if let Some(ty) = ty {
ty.is_primitive_ty()
|| matches!(ty, TyKind::Path(path_ty) if is_segment_representable(path_ty.path().path_ty()))
} else {
true
}
}
if value.self_ty.is_some() && is_segment_representable(value.path_ty.copy()) {
Err(())
} else {
Ok(&value.path)
}
}
}
#[cfg(feature = "driver-api")]
impl<'ast> AstQPath<'ast> {
pub fn new(
self_ty: Option<TyKind<'ast>>,
path_ty: Option<TyKind<'ast>>,
path: AstPath<'ast>,
target: AstPathTarget,
) -> Self {
Self {
self_ty: self_ty.into(),
path_ty: path_ty.into(),
path,
target,
}
}
}
#[repr(C)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
pub enum AstPathTarget {
SelfTy(ItemId),
Item(ItemId),
Variant(VariantId),
Var(VarId),
Generic(GenericId),
Unresolved,
}
#[repr(C)]
#[derive(Debug)]
pub struct AstPath<'ast> {
segments: FfiSlice<'ast, AstPathSegment<'ast>>,
}
#[cfg(feature = "driver-api")]
impl<'ast> AstPath<'ast> {
pub fn new(segments: &'ast [AstPathSegment<'ast>]) -> Self {
debug_assert!(!segments.is_empty());
Self {
segments: segments.into(),
}
}
}
impl<'ast> AstPath<'ast> {
pub fn segments(&self) -> &[AstPathSegment<'ast>] {
self.segments.get()
}
pub fn generics(&self) -> &GenericArgs<'ast> {
self.segments
.get()
.last()
.expect("a path always has at least one segment")
.generics()
}
}
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(feature = "driver-api", derive(Clone))]
pub struct AstPathSegment<'ast> {
ident: Ident<'ast>,
generics: GenericArgs<'ast>,
}
#[cfg(feature = "driver-api")]
impl<'ast> AstPathSegment<'ast> {
pub fn new(ident: Ident<'ast>, generics: GenericArgs<'ast>) -> Self {
Self { ident, generics }
}
}
impl<'ast> AstPathSegment<'ast> {
pub fn ident(&self) -> &Ident<'ast> {
&self.ident
}
pub fn generics(&self) -> &GenericArgs<'ast> {
&self.generics
}
}