Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ty_position.rs   Sprache: unbekannt

 
use super::lifetimes::{Lifetime, Lifetimes, MaybeStatic};
use super::{
    Borrow, LinkedLifetimes, MaybeOwn, Mutability, OutStructId, ReturnableStructPath, StructId,
    StructPath, TypeContext, TypeId,
};
use core::fmt::Debug;

/// Abstraction over where a type can appear in a function signature.
///
/// # "Output only" and "everywhere" types
///
/// While Rust is able to give up ownership of values, languages that Diplomat
/// supports (C++, Javascript, etc.) generally cannot. For example, we can
/// construct a `Box<MyOpaque>` in a Rust function and _return_ it to the other
/// language as a pointer. However, we cannot _accept_ `Box<MyOpaque>` as an input
/// because there's nothing stopping other languages from using that value again.
/// Therefore, we classify boxed opaques as "output only" types, since they can
/// only be returned from Rust but not taken as inputs.
///
/// Furthermore, Diplomat also supports "bag o' stuff" structs where all fields get
/// translated at the boundary. If one contains an "output only" type as a field,
/// then the whole struct must also be "output only". In particular, this means
/// that if a boxed opaque is nested in a bunch of "bag o' stuff" structs, than
/// all of those structs must also be "output only".
///
/// Currently, there are only two classes of structs: those that are "output only",
/// and those that are not. These are represented by the types [`OutputOnly`]
/// and [`Everywhere`] marker types respectively, which are the _only_ two types
/// that implement [`TyPosition`].
///
/// # How does abstraction help?
///
/// The HIR was designed around the idea of making invalid states unrepresentable.
/// Since "output only" types can contain values that "everywhere" types cannot,
/// it doesn't make sense for them to be represented in the same type, even if
/// they're mostly the same. One of these differences is that opaques (which are
/// always behind a pointer) can only be represented as a borrow in "everywhere"
/// types, but can additionally be represented as owned in "output only" types.
/// If we were to use the same type for both, then backends working with "everywhere"
/// types would constantly have unreachable statements for owned opaque cases.
///
/// That being said, "output only" and "everywhere" types are still mostly the
/// same, so this trait allows us to describe the differences. For example, the
/// HIR uses a singular [`Type`](super::Type) type for representing both
/// "output only" types and "everywhere" types, since it takes advantage of this
/// traits associated types to "fill in" the different parts:
/// ```ignore
/// pub enum Type<P: TyPosition = Everywhere> {
///     Primitive(PrimitiveType),
///     Opaque(OpaquePath<Optional, P::OpaqueOwnership>),
///     Struct(P::StructPath),
///     Enum(EnumPath),
///     Slice(Slice),
/// }
/// ```
///
/// When `P` takes on [`Everywhere`], this signature becomes:
/// ```ignore
/// pub enum Type {
///     Primitive(PrimitiveType),
///     Opaque(OpaquePath<Optional, Borrow>),
///     Struct(StructPath),
///     Enum(EnumPath),
///     Slice(Slice),
/// }
/// ```
///
/// This allows us to represent any kind of type that can appear "everywhere"
/// i.e. in inputs or outputs. Notice how the second generic in the `Opaque`
/// variant becomes [`Borrow`]. This describes the semantics of the pointer that
/// the opaque lives behind, and shows that for "everywhere" types, opaques
/// can _only_ be represented as living behind a borrow.
///
/// Contrast this to when `P` takes on [`OutputOnly`]:
/// ```ignore
/// pub enum Type {
///     Primitive(PrimitiveType),
///     Opaque(OpaquePath<Optional, MaybeOwn>),
///     Struct(OutStructPath),
///     Enum(EnumPath),
///     Slice(Slice),
/// }
/// ```
/// Here, the second generic of the `Opaque` variant becomes [`MaybeOwn`], meaning
/// that "output only" types can contain opaques that are either borrowed _or_ owned.
///
/// Therefore, this trait allows be extremely precise about making invalid states
/// unrepresentable, while also reducing duplicated code.
///
pub trait TyPosition: Debug + Copy {
    const IS_OUT_ONLY: bool;

    /// Type representing how we can point to opaques, which must always be behind a pointer.
    ///
    /// The types represented by [`OutputOnly`] are capable of either owning or
    /// borrowing opaques, and so the associated type for that impl is [`MaybeOwn`].
    ///
    /// On the other hand, types represented by [`Everywhere`] can only contain
    /// borrowes, so the associated type for that impl is [`Borrow`].
    type OpaqueOwnership: Debug + OpaqueOwner;

    type StructId: Debug;

    type StructPath: Debug + StructPathLike;
}

/// One of two types implementing [`TyPosition`], representing types that can be
/// used as both input and output to functions.
///
/// The complement of this type is [`OutputOnly`].
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub struct Everywhere;

/// One of two types implementing [`TyPosition`], representing types that can
/// only be used as return types in functions.
///
/// The complement of this type is [`Everywhere`].
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub struct OutputOnly;

impl TyPosition for Everywhere {
    const IS_OUT_ONLY: bool = false;
    type OpaqueOwnership = Borrow;
    type StructId = StructId;
    type StructPath = StructPath;
}

impl TyPosition for OutputOnly {
    const IS_OUT_ONLY: bool = true;
    type OpaqueOwnership = MaybeOwn;
    type StructId = OutStructId;
    type StructPath = ReturnableStructPath;
}

pub trait StructPathLike {
    fn lifetimes(&self) -> &Lifetimes;
    fn id(&self) -> TypeId;

    /// Get a map of lifetimes used on this path to lifetimes as named in the def site. See [`LinkedLifetimes`]
    /// for more information.
    fn link_lifetimes<'def, 'tcx>(
        &'def self,
        tcx: &'tcx TypeContext,
    ) -> LinkedLifetimes<'def, 'tcx>;
}

impl StructPathLike for StructPath {
    fn lifetimes(&self) -> &Lifetimes {
        &self.lifetimes
    }
    fn id(&self) -> TypeId {
        self.tcx_id.into()
    }

    fn link_lifetimes<'def, 'tcx>(
        &'def self,
        tcx: &'tcx TypeContext,
    ) -> LinkedLifetimes<'def, 'tcx> {
        let struc = self.resolve(tcx);
        let env = &struc.lifetimes;
        LinkedLifetimes::new(env, None, &self.lifetimes)
    }
}

impl StructPathLike for ReturnableStructPath {
    fn lifetimes(&self) -> &Lifetimes {
        self.lifetimes()
    }
    fn id(&self) -> TypeId {
        match self {
            ReturnableStructPath::Struct(p) => p.tcx_id.into(),
            ReturnableStructPath::OutStruct(p) => p.tcx_id.into(),
        }
    }

    fn link_lifetimes<'def, 'tcx>(
        &'def self,
        tcx: &'tcx TypeContext,
    ) -> LinkedLifetimes<'def, 'tcx> {
        match self {
            Self::Struct(p) => p.link_lifetimes(tcx),
            Self::OutStruct(p) => p.link_lifetimes(tcx),
        }
    }
}
/// Abstraction over how a type can hold a pointer to an opaque.
///
/// This trait is designed as a helper abstraction for the `OpaqueOwnership`
/// associated type in the [`TyPosition`] trait. As such, only has two implementing
/// types: [`MaybeOwn`] and [`Borrow`] for the [`OutputOnly`] and [`Everywhere`]
/// implementations of [`TyPosition`] respectively.
pub trait OpaqueOwner {
    /// Return the mutability of this owner
    fn mutability(&self) -> Option<Mutability>;

    fn is_owned(&self) -> bool;

    /// Return the lifetime of the borrow, if any.
    fn lifetime(&self) -> Option<MaybeStatic<Lifetime>>;
}

impl OpaqueOwner for MaybeOwn {
    fn mutability(&self) -> Option<Mutability> {
        match self {
            MaybeOwn::Own => None,
            MaybeOwn::Borrow(b) => b.mutability(),
        }
    }

    fn is_owned(&self) -> bool {
        match self {
            MaybeOwn::Own => true,
            MaybeOwn::Borrow(_) => false,
        }
    }

    fn lifetime(&self) -> Option<MaybeStatic<Lifetime>> {
        match self {
            MaybeOwn::Own => None,
            MaybeOwn::Borrow(b) => b.lifetime(),
        }
    }
}

impl OpaqueOwner for Borrow {
    fn mutability(&self) -> Option<Mutability> {
        Some(self.mutability)
    }

    fn is_owned(&self) -> bool {
        false
    }

    fn lifetime(&self) -> Option<MaybeStatic<Lifetime>> {
        Some(self.lifetime)
    }
}

[ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge