tamer: asg::graph::object::ObjectIndexRefined: New narrowing type
The provided documentation provides rationale, and the use case is the ontree change. I was uncomfortable without the exhaustive match, and I was further annoyed by the lack of easy `ObjectIndex` narrowing. DEV-13163main
parent
5a301c1548
commit
507669cb30
|
@ -243,6 +243,20 @@ macro_rules! object_gen {
|
|||
}
|
||||
}
|
||||
|
||||
/// Narrowed [`ObjectIndex`] types for each [`ObjectKind`].
|
||||
///
|
||||
/// This allows for converting a dynamic
|
||||
/// [`ObjectIndex<Object>`](ObjectIndex) into a statically known
|
||||
/// [`ObjectKind`],
|
||||
/// while also providing the ability to exhaustively match
|
||||
/// against all such possibilities.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ObjectIndexRefined {
|
||||
$(
|
||||
$kind(ObjectIndex<$kind>),
|
||||
)+
|
||||
}
|
||||
|
||||
/// The collection of potential objects of [`Object`].
|
||||
pub trait ObjectInner {
|
||||
$(type $kind;)+
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
//! See (parent module)[super] for more information.
|
||||
|
||||
use super::{
|
||||
Doc, Expr, Ident, Meta, Object, ObjectIndex, ObjectKind, OiPairObjectInner,
|
||||
Pkg, Root,
|
||||
Doc, Expr, Ident, Meta, Object, ObjectIndex, ObjectIndexRefined,
|
||||
ObjectKind, OiPairObjectInner, Pkg, Root,
|
||||
};
|
||||
use crate::{
|
||||
asg::{graph::object::Tpl, Asg},
|
||||
|
@ -270,12 +270,47 @@ impl<S> DynObjectRel<S, ObjectIndex<Object>> {
|
|||
/// Attempt to narrow the target into the [`ObjectRel`] of `O`.
|
||||
///
|
||||
/// See [`ObjectRelatable::new_rel_dyn`] for more information.
|
||||
///
|
||||
/// To exhaustively match against all possible [`ObjectKind`]s,
|
||||
/// see [`Self::refine_target`].
|
||||
pub fn narrow_target<O: ObjectKind + ObjectRelatable>(
|
||||
&self,
|
||||
) -> Option<O::Rel> {
|
||||
O::new_rel_dyn(self.target_ty(), *self.target())
|
||||
}
|
||||
|
||||
/// Refine the target [`ObjectIndex<Object>`](ObjectIndex) into
|
||||
/// [`ObjectIndexRefined`] such that the returned variant has a
|
||||
/// narrowed [`ObjectIndex<O>`] type.
|
||||
///
|
||||
/// This allows converting a dynamic [`ObjectIndex`] into a statically
|
||||
/// known type where `O` is derived from [`Self::target_ty`].
|
||||
/// This avoids having to manually match on [`Self::target_ty`] and then
|
||||
/// use [`ObjectIndex::must_narrow_into`] on the matching
|
||||
/// [`ObjectKind`],
|
||||
/// since there is a risk of those getting out of sync.
|
||||
///
|
||||
/// In contrast to [`Self::narrow_target`],
|
||||
/// where the caller must specify the expected [`ObjectKind`],
|
||||
/// this allows for exhaustively matching against all possible objects.
|
||||
pub fn refine_target(&self) -> ObjectIndexRefined {
|
||||
macro_rules! narrow_each_rel_ty {
|
||||
( $($var:ident),+ ) => {
|
||||
match self.target_ty() {
|
||||
$(
|
||||
ObjectRelTy::$var => {
|
||||
ObjectIndexRefined::$var(
|
||||
self.target().must_narrow_into()
|
||||
)
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
narrow_each_rel_ty!(Root, Pkg, Ident, Expr, Tpl, Meta, Doc)
|
||||
}
|
||||
|
||||
/// Attempt to convert [`Self`] into an [`ObjectIndex`] with an
|
||||
/// [`ObjectKind`] of type `O`.
|
||||
///
|
||||
|
|
|
@ -324,6 +324,8 @@ impl Token for TreeWalkRel {
|
|||
impl parse::Object for TreeWalkRel {}
|
||||
|
||||
mod order {
|
||||
use crate::asg::graph::object::ObjectIndexRefined;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Emit edges in the same order that they were added to the graph.
|
||||
|
@ -437,14 +439,13 @@ mod order {
|
|||
depth: Depth,
|
||||
stack: &mut Vec<(DynObjectRel, Depth)>,
|
||||
) {
|
||||
use ObjectTy::*;
|
||||
|
||||
// We start by adding edges to the stack in natural order,
|
||||
// remembering the original stack offset so that we can sort
|
||||
// just the portion that we added.
|
||||
let offset = stack.len();
|
||||
NaturalTreeEdgeOrder::push_edges_of(asg, rel, depth, stack);
|
||||
|
||||
use ObjectTy::*;
|
||||
match rel.target_ty() {
|
||||
// Templates require partial ordering into a header and a body.
|
||||
Tpl => {
|
||||
|
@ -485,20 +486,23 @@ mod order {
|
|||
// definitions,
|
||||
// which are not all that common relative to
|
||||
// everything else).
|
||||
use ObjectIndexRefined::*;
|
||||
part.sort_by_cached_key(|(child_rel, _)| {
|
||||
if let Some(ident) =
|
||||
child_rel.filter_into_target::<object::Ident>()
|
||||
{
|
||||
// This is the (comparatively) expensive lookup,
|
||||
// requiring a small graph traversal.
|
||||
match ident.definition::<object::Meta>(asg) {
|
||||
Some(_) => TplOrder::Param,
|
||||
None => TplOrder::Body,
|
||||
match child_rel.refine_target() {
|
||||
Ident(oi_ident) => {
|
||||
// This is the (comparatively) expensive lookup,
|
||||
// requiring a small graph traversal.
|
||||
match oi_ident.definition::<object::Meta>(asg) {
|
||||
Some(_) => TplOrder::Param,
|
||||
None => TplOrder::Body,
|
||||
}
|
||||
}
|
||||
|
||||
Doc(_) => TplOrder::TplDesc,
|
||||
|
||||
Root(_) | Pkg(_) | Expr(_) | Tpl(_) | Meta(_) => {
|
||||
TplOrder::Body
|
||||
}
|
||||
} else if child_rel.target_ty() == Doc {
|
||||
TplOrder::TplDesc
|
||||
} else {
|
||||
TplOrder::Body
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue