///|
pub(all) struct NativeStubSourcePhaseRule {
phase : String
files : Array[String]
expected_symbols : Array[String]
} derive(Eq, Debug)
///|
pub(all) struct NativeStubSourcePhasePolicyReport {
rule_count : Int
actual_fact_count : Int
actual_phase_count : Int
expected_symbol_count : Int
phase1_symbol_count : Int
phase2_symbol_count : Int
phase3_symbol_count : Int
missing_symbol_count : Int
extra_symbol_count : Int
unknown_file_count : Int
duplicate_symbol_fact_count : Int
replaces_file_reading : Bool
replaces_function_extraction : Bool
live_io_evidence : Bool
} derive(Eq, Debug)
///|
pub fn NativeStubSourcePhasePolicyReport::passes(
self : NativeStubSourcePhasePolicyReport,
) -> Bool {
self.rule_count == 3 &&
self.actual_phase_count == self.rule_count &&
self.expected_symbol_count > 0 &&
self.phase1_symbol_count > 0 &&
self.phase2_symbol_count > 0 &&
self.phase3_symbol_count > 0 &&
self.missing_symbol_count == 0 &&
self.extra_symbol_count == 0 &&
self.unknown_file_count == 0 &&
self.duplicate_symbol_fact_count == 0 &&
!self.replaces_file_reading &&
!self.replaces_function_extraction &&
!self.live_io_evidence
}
///|
pub fn native_stub_source_phase_rules() -> Array[NativeStubSourcePhaseRule] {
[
{
phase: "phase1-platform",
files: ["stub_npcap_windows_loader.c", "stub_npcap_windows_common.c"],
expected_symbols: [
"lockwire_native_npcap_ensure", "lockwire_native_npcap_findalldevs", "lockwire_native_npcap_freealldevs",
"lockwire_native_npcap_live_ensure", "lockwire_native_npcap_open_live_handle",
"lockwire_native_npcap_close_handle", "lockwire_native_npcap_sendpacket_handle",
"lockwire_native_npcap_next_ex_handle", "lockwire_native_npcap_geterr_handle",
"lockwire_native_npcap_compile_filter_handle", "lockwire_native_npcap_setfilter_handle",
"lockwire_native_npcap_freecode_handle", "lockwire_native_npcap_probe_implemented",
"lockwire_native_npcap_runtime_available", "lockwire_native_npcap_live_handle_get",
"lockwire_native_npcap_live_handle_alloc", "lockwire_native_npcap_live_handle_release",
"lockwire_native_npcap_copy_moonbit_bytes_to_c_string",
],
},
{
phase: "phase2-execution",
files: [
"stub_npcap_windows_listing.c", "stub_npcap_windows_live.c", "stub_npcap_windows_live_send.c",
"stub_npcap_windows_live_filter.c", "stub_npcap_windows_live_capture.c",
],
expected_symbols: [
"lockwire_native_npcap_list_interfaces_text", "lockwire_native_npcap_live_adapter_implemented",
"lockwire_native_npcap_open_live", "lockwire_native_npcap_close_live", "lockwire_native_npcap_send_packet",
"lockwire_native_npcap_set_filter", "lockwire_native_npcap_capture_one",
],
},
{
phase: "phase3-fallback",
files: ["stub_npcap_unsupported.c"],
expected_symbols: native_stub_npcap_public_roster(),
},
]
}
///|
pub fn native_stub_expected_source_phase_facts() -> Array[
NativeStubSourceFunctionFact,
] {
let facts : Array[NativeStubSourceFunctionFact] = []
push_source_phase_file_facts(facts, "stub_npcap_windows_loader.c", [
"lockwire_native_npcap_ensure", "lockwire_native_npcap_findalldevs", "lockwire_native_npcap_freealldevs",
"lockwire_native_npcap_live_ensure", "lockwire_native_npcap_open_live_handle",
"lockwire_native_npcap_close_handle", "lockwire_native_npcap_sendpacket_handle",
"lockwire_native_npcap_next_ex_handle", "lockwire_native_npcap_geterr_handle",
"lockwire_native_npcap_compile_filter_handle", "lockwire_native_npcap_setfilter_handle",
"lockwire_native_npcap_freecode_handle", "lockwire_native_npcap_probe_implemented",
"lockwire_native_npcap_runtime_available",
])
push_source_phase_file_facts(facts, "stub_npcap_windows_common.c", [
"lockwire_native_npcap_live_handle_get", "lockwire_native_npcap_live_handle_alloc",
"lockwire_native_npcap_live_handle_release", "lockwire_native_npcap_copy_moonbit_bytes_to_c_string",
])
push_source_phase_file_facts(facts, "stub_npcap_windows_listing.c", [
"lockwire_native_npcap_list_interfaces_text",
])
push_source_phase_file_facts(facts, "stub_npcap_windows_live.c", [
"lockwire_native_npcap_live_adapter_implemented", "lockwire_native_npcap_open_live",
"lockwire_native_npcap_close_live",
])
push_source_phase_file_facts(facts, "stub_npcap_windows_live_send.c", [
"lockwire_native_npcap_send_packet",
])
push_source_phase_file_facts(facts, "stub_npcap_windows_live_filter.c", [
"lockwire_native_npcap_set_filter",
])
push_source_phase_file_facts(facts, "stub_npcap_windows_live_capture.c", [
"lockwire_native_npcap_capture_one",
])
push_source_phase_file_facts(
facts,
"stub_npcap_unsupported.c",
native_stub_npcap_public_roster(),
)
facts
}
///|
pub fn native_stub_source_phase_policy_report(
actual : Array[NativeStubSourceFunctionFact],
) -> NativeStubSourcePhasePolicyReport {
native_stub_source_phase_policy_report_from_rules(
native_stub_source_phase_rules(),
actual,
)
}
///|
pub fn native_stub_source_phase_policy_report_from_rules(
rules : Array[NativeStubSourcePhaseRule],
actual : Array[NativeStubSourceFunctionFact],
) -> NativeStubSourcePhasePolicyReport {
{
rule_count: rules.length(),
actual_fact_count: actual.length(),
actual_phase_count: count_actual_source_phases(rules, actual),
expected_symbol_count: count_expected_source_phase_symbols(rules),
phase1_symbol_count: count_source_phase_symbols(
rules, actual, "phase1-platform",
),
phase2_symbol_count: count_source_phase_symbols(
rules, actual, "phase2-execution",
),
phase3_symbol_count: count_source_phase_symbols(
rules, actual, "phase3-fallback",
),
missing_symbol_count: count_missing_source_phase_symbols(rules, actual),
extra_symbol_count: count_extra_source_phase_symbols(rules, actual),
unknown_file_count: count_unknown_source_phase_files(rules, actual),
duplicate_symbol_fact_count: count_duplicate_source_phase_facts(actual),
replaces_file_reading: false,
replaces_function_extraction: false,
live_io_evidence: false,
}
}
///|
fn native_stub_npcap_public_roster() -> Array[String] {
[
"lockwire_native_npcap_probe_implemented", "lockwire_native_npcap_runtime_available",
"lockwire_native_npcap_list_interfaces_text", "lockwire_native_npcap_live_adapter_implemented",
"lockwire_native_npcap_open_live", "lockwire_native_npcap_send_packet", "lockwire_native_npcap_set_filter",
"lockwire_native_npcap_capture_one", "lockwire_native_npcap_close_live",
]
}
///|
fn push_source_phase_file_facts(
facts : Array[NativeStubSourceFunctionFact],
file : String,
symbols : Array[String],
) -> Unit {
for symbol in symbols {
facts.push({ file, symbol })
}
}
///|
fn count_actual_source_phases(
rules : Array[NativeStubSourcePhaseRule],
actual : Array[NativeStubSourceFunctionFact],
) -> Int {
let phases : Array[String] = []
for fact in actual {
let phase = source_phase_for_file(rules, fact.file)
if phase != "" && !source_phase_contains_string(phases, phase) {
phases.push(phase)
}
}
phases.length()
}
///|
fn count_expected_source_phase_symbols(
rules : Array[NativeStubSourcePhaseRule],
) -> Int {
let mut count = 0
for rule in rules {
count += rule.expected_symbols.length()
}
count
}
///|
fn count_source_phase_symbols(
rules : Array[NativeStubSourcePhaseRule],
actual : Array[NativeStubSourceFunctionFact],
phase : String,
) -> Int {
let symbols : Array[String] = []
for rule in rules {
if rule.phase == phase {
for fact in actual {
if source_phase_rule_contains_file(rule, fact.file) &&
!source_phase_contains_string(symbols, fact.symbol) {
symbols.push(fact.symbol)
}
}
}
}
symbols.length()
}
///|
fn count_missing_source_phase_symbols(
rules : Array[NativeStubSourcePhaseRule],
actual : Array[NativeStubSourceFunctionFact],
) -> Int {
let mut count = 0
for rule in rules {
for symbol in rule.expected_symbols {
if !source_phase_contains_symbol(actual, rule, symbol) {
count += 1
}
}
}
count
}
///|
fn count_extra_source_phase_symbols(
rules : Array[NativeStubSourcePhaseRule],
actual : Array[NativeStubSourceFunctionFact],
) -> Int {
let mut count = 0
for fact in actual {
let mut known_file = false
let mut allowed = false
for rule in rules {
if source_phase_rule_contains_file(rule, fact.file) {
known_file = true
if source_phase_contains_string(rule.expected_symbols, fact.symbol) {
allowed = true
}
}
}
if known_file && !allowed {
count += 1
}
}
count
}
///|
fn count_unknown_source_phase_files(
rules : Array[NativeStubSourcePhaseRule],
actual : Array[NativeStubSourceFunctionFact],
) -> Int {
let files : Array[String] = []
for fact in actual {
if !source_phase_file_is_known(rules, fact.file) &&
!source_phase_contains_string(files, fact.file) {
files.push(fact.file)
}
}
files.length()
}
///|
fn count_duplicate_source_phase_facts(
actual : Array[NativeStubSourceFunctionFact],
) -> Int {
let seen : Array[NativeStubSourceFunctionFact] = []
let mut count = 0
for fact in actual {
if source_phase_contains_fact(seen, fact.file, fact.symbol) {
count += 1
} else {
seen.push(fact)
}
}
count
}
///|
fn source_phase_contains_symbol(
actual : Array[NativeStubSourceFunctionFact],
rule : NativeStubSourcePhaseRule,
symbol : String,
) -> Bool {
for fact in actual {
if fact.symbol == symbol && source_phase_rule_contains_file(rule, fact.file) {
return true
}
}
false
}
///|
fn source_phase_for_file(
rules : Array[NativeStubSourcePhaseRule],
file : String,
) -> String {
for rule in rules {
if source_phase_rule_contains_file(rule, file) {
return rule.phase
}
}
""
}
///|
fn source_phase_file_is_known(
rules : Array[NativeStubSourcePhaseRule],
file : String,
) -> Bool {
for rule in rules {
if source_phase_rule_contains_file(rule, file) {
return true
}
}
false
}
///|
fn source_phase_rule_contains_file(
rule : NativeStubSourcePhaseRule,
file : String,
) -> Bool {
for got in rule.files {
if got == file {
return true
}
}
false
}
///|
fn source_phase_contains_fact(
facts : Array[NativeStubSourceFunctionFact],
file : String,
symbol : String,
) -> Bool {
for fact in facts {
if fact.file == file && fact.symbol == symbol {
return true
}
}
false
}
///|
fn source_phase_contains_string(items : Array[String], item : String) -> Bool {
for got in items {
if got == item {
return true
}
}
false
}