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`].
|
/// The collection of potential objects of [`Object`].
|
||||||
pub trait ObjectInner {
|
pub trait ObjectInner {
|
||||||
$(type $kind;)+
|
$(type $kind;)+
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
//! See (parent module)[super] for more information.
|
//! See (parent module)[super] for more information.
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Doc, Expr, Ident, Meta, Object, ObjectIndex, ObjectKind, OiPairObjectInner,
|
Doc, Expr, Ident, Meta, Object, ObjectIndex, ObjectIndexRefined,
|
||||||
Pkg, Root,
|
ObjectKind, OiPairObjectInner, Pkg, Root,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
asg::{graph::object::Tpl, Asg},
|
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`.
|
/// Attempt to narrow the target into the [`ObjectRel`] of `O`.
|
||||||
///
|
///
|
||||||
/// See [`ObjectRelatable::new_rel_dyn`] for more information.
|
/// 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>(
|
pub fn narrow_target<O: ObjectKind + ObjectRelatable>(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<O::Rel> {
|
) -> Option<O::Rel> {
|
||||||
O::new_rel_dyn(self.target_ty(), *self.target())
|
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
|
/// Attempt to convert [`Self`] into an [`ObjectIndex`] with an
|
||||||
/// [`ObjectKind`] of type `O`.
|
/// [`ObjectKind`] of type `O`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -324,6 +324,8 @@ impl Token for TreeWalkRel {
|
||||||
impl parse::Object for TreeWalkRel {}
|
impl parse::Object for TreeWalkRel {}
|
||||||
|
|
||||||
mod order {
|
mod order {
|
||||||
|
use crate::asg::graph::object::ObjectIndexRefined;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Emit edges in the same order that they were added to the graph.
|
/// Emit edges in the same order that they were added to the graph.
|
||||||
|
@ -437,14 +439,13 @@ mod order {
|
||||||
depth: Depth,
|
depth: Depth,
|
||||||
stack: &mut Vec<(DynObjectRel, Depth)>,
|
stack: &mut Vec<(DynObjectRel, Depth)>,
|
||||||
) {
|
) {
|
||||||
use ObjectTy::*;
|
|
||||||
|
|
||||||
// We start by adding edges to the stack in natural order,
|
// We start by adding edges to the stack in natural order,
|
||||||
// remembering the original stack offset so that we can sort
|
// remembering the original stack offset so that we can sort
|
||||||
// just the portion that we added.
|
// just the portion that we added.
|
||||||
let offset = stack.len();
|
let offset = stack.len();
|
||||||
NaturalTreeEdgeOrder::push_edges_of(asg, rel, depth, stack);
|
NaturalTreeEdgeOrder::push_edges_of(asg, rel, depth, stack);
|
||||||
|
|
||||||
|
use ObjectTy::*;
|
||||||
match rel.target_ty() {
|
match rel.target_ty() {
|
||||||
// Templates require partial ordering into a header and a body.
|
// Templates require partial ordering into a header and a body.
|
||||||
Tpl => {
|
Tpl => {
|
||||||
|
@ -485,20 +486,23 @@ mod order {
|
||||||
// definitions,
|
// definitions,
|
||||||
// which are not all that common relative to
|
// which are not all that common relative to
|
||||||
// everything else).
|
// everything else).
|
||||||
|
use ObjectIndexRefined::*;
|
||||||
part.sort_by_cached_key(|(child_rel, _)| {
|
part.sort_by_cached_key(|(child_rel, _)| {
|
||||||
if let Some(ident) =
|
match child_rel.refine_target() {
|
||||||
child_rel.filter_into_target::<object::Ident>()
|
Ident(oi_ident) => {
|
||||||
{
|
// This is the (comparatively) expensive lookup,
|
||||||
// This is the (comparatively) expensive lookup,
|
// requiring a small graph traversal.
|
||||||
// requiring a small graph traversal.
|
match oi_ident.definition::<object::Meta>(asg) {
|
||||||
match ident.definition::<object::Meta>(asg) {
|
Some(_) => TplOrder::Param,
|
||||||
Some(_) => TplOrder::Param,
|
None => TplOrder::Body,
|
||||||
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