mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-30 20:28:11 -07:00
clients: snapshot
This commit is contained in:
@@ -123,6 +123,9 @@ pub struct PatternBaseResult {
|
||||
/// Whether this instance uses suffix mode (common prefix) or prefix mode (common suffix).
|
||||
/// Used to check compatibility with the pattern's mode.
|
||||
pub is_suffix_mode: bool,
|
||||
/// The field parts (suffix in suffix mode, prefix in prefix mode) for each field.
|
||||
/// Used to check if instance field parts match the pattern's field parts.
|
||||
pub field_parts: HashMap<String, String>,
|
||||
}
|
||||
|
||||
/// Get the metric base for a pattern instance by analyzing direct children.
|
||||
@@ -141,6 +144,7 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
base: String::new(),
|
||||
has_outlier: false,
|
||||
is_suffix_mode: true, // default
|
||||
field_parts: HashMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -150,6 +154,7 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
base: result.base,
|
||||
has_outlier: result.has_outlier,
|
||||
is_suffix_mode: result.is_suffix_mode,
|
||||
field_parts: result.field_parts,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -168,6 +173,7 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
base: result.base,
|
||||
has_outlier: true,
|
||||
is_suffix_mode: result.is_suffix_mode,
|
||||
field_parts: result.field_parts,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -179,14 +185,16 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
|
||||
base: String::new(),
|
||||
has_outlier: false,
|
||||
is_suffix_mode: true, // default
|
||||
field_parts: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of try_find_base: base name, has_outlier flag, and is_suffix_mode flag.
|
||||
/// Result of try_find_base: base name, has_outlier flag, is_suffix_mode flag, and field_parts.
|
||||
struct FindBaseResult {
|
||||
base: String,
|
||||
has_outlier: bool,
|
||||
is_suffix_mode: bool,
|
||||
field_parts: HashMap<String, String>,
|
||||
}
|
||||
|
||||
/// Try to find a common base from child names using prefix/suffix detection.
|
||||
@@ -197,20 +205,52 @@ fn try_find_base(child_names: &[(String, String)], is_outlier_attempt: bool) ->
|
||||
// Try common prefix first (suffix mode)
|
||||
if let Some(prefix) = find_common_prefix(&leaf_names) {
|
||||
let base = prefix.trim_end_matches('_').to_string();
|
||||
let mut field_parts = HashMap::new();
|
||||
for (field_name, leaf_name) in child_names {
|
||||
// Compute the suffix part for this field
|
||||
let suffix = if leaf_name == &base {
|
||||
String::new()
|
||||
} else {
|
||||
leaf_name
|
||||
.strip_prefix(&prefix)
|
||||
.unwrap_or(leaf_name)
|
||||
.to_string()
|
||||
};
|
||||
field_parts.insert(field_name.clone(), suffix);
|
||||
}
|
||||
return Some(FindBaseResult {
|
||||
base,
|
||||
has_outlier: is_outlier_attempt,
|
||||
is_suffix_mode: true,
|
||||
field_parts,
|
||||
});
|
||||
}
|
||||
|
||||
// Try common suffix (prefix mode)
|
||||
if let Some(suffix) = find_common_suffix(&leaf_names) {
|
||||
let base = suffix.trim_start_matches('_').to_string();
|
||||
let mut field_parts = HashMap::new();
|
||||
for (field_name, leaf_name) in child_names {
|
||||
// Compute the prefix part for this field
|
||||
let prefix_part = leaf_name
|
||||
.strip_suffix(&suffix)
|
||||
.map(|s| {
|
||||
if s.is_empty() {
|
||||
String::new()
|
||||
} else if s.ends_with('_') {
|
||||
s.to_string()
|
||||
} else {
|
||||
format!("{}_", s)
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
field_parts.insert(field_name.clone(), prefix_part);
|
||||
}
|
||||
return Some(FindBaseResult {
|
||||
base,
|
||||
has_outlier: is_outlier_attempt,
|
||||
is_suffix_mode: false,
|
||||
field_parts,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -55,17 +55,20 @@ pub fn prepare_tree_node<'a>(
|
||||
.map(|(f, _)| f.clone())
|
||||
.collect();
|
||||
|
||||
// Skip if this matches a parameterizable pattern AND has no outlier AND mode matches
|
||||
// Skip if this matches a parameterizable pattern AND has no outlier AND field parts match
|
||||
let base_result = get_pattern_instance_base(node);
|
||||
let mode_matches = pattern_lookup
|
||||
let pattern_fully_matches = pattern_lookup
|
||||
.get(&fields)
|
||||
.and_then(|name| metadata.find_pattern(name))
|
||||
.is_none_or(|p| p.is_suffix_mode() == base_result.is_suffix_mode);
|
||||
.is_some_and(|p| {
|
||||
p.is_suffix_mode() == base_result.is_suffix_mode
|
||||
&& p.field_parts_match(&base_result.field_parts)
|
||||
});
|
||||
if let Some(pattern_name) = pattern_lookup.get(&fields)
|
||||
&& pattern_name != name
|
||||
&& metadata.is_parameterizable(pattern_name)
|
||||
&& !base_result.has_outlier
|
||||
&& mode_matches
|
||||
&& pattern_fully_matches
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -89,16 +92,23 @@ pub fn prepare_tree_node<'a>(
|
||||
.as_ref()
|
||||
.is_some_and(|cf| metadata.matches_pattern(cf));
|
||||
|
||||
// Check if the pattern mode matches the instance mode
|
||||
let mode_matches = child_fields
|
||||
// Check if the pattern mode AND field parts match the instance
|
||||
let pattern_fully_matches = child_fields
|
||||
.as_ref()
|
||||
.and_then(|cf| metadata.find_pattern_by_fields(cf))
|
||||
.is_none_or(|p| p.is_suffix_mode() == base_result.is_suffix_mode);
|
||||
.is_some_and(|p| {
|
||||
// Mode must match (suffix vs prefix)
|
||||
if p.is_suffix_mode() != base_result.is_suffix_mode {
|
||||
return false;
|
||||
}
|
||||
// Field parts must also match
|
||||
p.field_parts_match(&base_result.field_parts)
|
||||
});
|
||||
|
||||
// should_inline determines if we generate an inline struct type
|
||||
// We inline if: it's a branch AND (doesn't match any pattern OR mode doesn't match OR has outlier)
|
||||
// We inline if: it's a branch AND (doesn't match any pattern OR pattern doesn't fully match OR has outlier)
|
||||
let should_inline =
|
||||
!is_leaf && (!matches_any_pattern || !mode_matches || base_result.has_outlier);
|
||||
!is_leaf && (!matches_any_pattern || !pattern_fully_matches || base_result.has_outlier);
|
||||
|
||||
// Inline type name (only used when should_inline is true)
|
||||
let inline_type_name = if should_inline {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Structural pattern and field types.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use brk_types::Index;
|
||||
|
||||
@@ -47,6 +47,30 @@ impl StructuralPattern {
|
||||
pub fn is_suffix_mode(&self) -> bool {
|
||||
matches!(&self.mode, Some(PatternMode::Suffix { .. }))
|
||||
}
|
||||
|
||||
/// Check if the given instance field parts match this pattern's field parts.
|
||||
/// Returns true if all field parts in the pattern match the instance's field parts.
|
||||
pub fn field_parts_match(&self, instance_field_parts: &HashMap<String, String>) -> bool {
|
||||
match &self.mode {
|
||||
Some(PatternMode::Suffix { relatives }) => {
|
||||
// For each field in the pattern, check if the instance has the same suffix
|
||||
relatives.iter().all(|(field_name, pattern_suffix)| {
|
||||
instance_field_parts
|
||||
.get(field_name)
|
||||
.is_some_and(|instance_suffix| instance_suffix == pattern_suffix)
|
||||
})
|
||||
}
|
||||
Some(PatternMode::Prefix { prefixes }) => {
|
||||
// For each field in the pattern, check if the instance has the same prefix
|
||||
prefixes.iter().all(|(field_name, pattern_prefix)| {
|
||||
instance_field_parts
|
||||
.get(field_name)
|
||||
.is_some_and(|instance_prefix| instance_prefix == pattern_prefix)
|
||||
})
|
||||
}
|
||||
None => false, // Non-parameterizable patterns don't use field parts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A field in a structural pattern.
|
||||
|
||||
Reference in New Issue
Block a user