///|
pub(all) struct NativeStubSourceTokenRule {
file : String
required_tokens : Array[String]
forbidden_tokens : Array[String]
} derive(Eq, Debug)
///|
pub(all) struct NativeStubSourceTokenFact {
file : String
token : String
present : Bool
} derive(Eq, Debug)
///|
pub(all) struct NativeStubSourceTokenPolicyReport {
rule_count : Int
actual_file_count : Int
missing_file_count : Int
extra_file_count : Int
required_token_count : Int
forbidden_token_count : Int
missing_required_token_count : Int
present_forbidden_token_count : Int
unexpected_token_fact_count : Int
duplicate_token_fact_count : Int
replaces_file_reading : Bool
replaces_token_extraction : Bool
live_io_evidence : Bool
} derive(Eq, Debug)
///|
pub fn NativeStubSourceTokenPolicyReport::passes(
self : NativeStubSourceTokenPolicyReport,
) -> Bool {
self.rule_count > 0 &&
self.actual_file_count == self.rule_count &&
self.missing_file_count == 0 &&
self.extra_file_count == 0 &&
self.required_token_count > 0 &&
self.forbidden_token_count > 0 &&
self.missing_required_token_count == 0 &&
self.present_forbidden_token_count == 0 &&
self.unexpected_token_fact_count == 0 &&
self.duplicate_token_fact_count == 0 &&
!self.replaces_file_reading &&
!self.replaces_token_extraction &&
!self.live_io_evidence
}
///|
pub fn native_stub_source_token_rules() -> Array[NativeStubSourceTokenRule] {
let rules : Array[NativeStubSourceTokenRule] = []
rules.push(
source_token_rule(
"stub_common.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_COMMON_H", "#define LOCKWIRE_NATIVE_STUB_COMMON_H",
"#define LOCKWIRE_NATIVE_OK 1",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule(
"stub_pcap.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_PCAP_H", "#define LOCKWIRE_NATIVE_STUB_PCAP_H",
"#define LOCKWIRE_MAX_PCAP_HANDLES 32",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule(
"stub_frame_pool.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_FRAME_POOL_H", "#define LOCKWIRE_NATIVE_STUB_FRAME_POOL_H",
"#define LOCKWIRE_NATIVE_FRAME_POOL_MAX_POOLS 16", "#define LOCKWIRE_NATIVE_FRAME_POOL_MAX_CAPACITY 128",
"#define LOCKWIRE_NATIVE_FRAME_POOL_MAX_FRAME_SIZE 65536",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule(
"stub_npcap_windows.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_NPCAP_WINDOWS_H", "#define LOCKWIRE_NATIVE_STUB_NPCAP_WINDOWS_H",
"#define LOCKWIRE_MAX_NPCAP_LIVE_HANDLES 32", "#define LOCKWIRE_NPCAP_LIVE_MAX_FRAME_SIZE 65536",
"#define LOCKWIRE_NPCAP_FILTER_MAX_EXPR_SIZE 4096",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule(
"stub_raw_socket_linux.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_RAW_SOCKET_LINUX_H", "#define LOCKWIRE_NATIVE_STUB_RAW_SOCKET_LINUX_H",
"#define LOCKWIRE_MAX_RAW_SOCKET_HANDLES 32", "#define LOCKWIRE_RAW_SOCKET_MAX_FRAME_SIZE 65535",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule(
"stub_udp_windows.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_UDP_WINDOWS_H", "#define LOCKWIRE_NATIVE_STUB_UDP_WINDOWS_H",
"#define LOCKWIRE_MAX_UDP_HANDLES 32", "#define LOCKWIRE_UDP_WSAETIMEDOUT 10060",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule(
"stub_udp_posix.h",
[
"#ifndef LOCKWIRE_NATIVE_STUB_UDP_POSIX_H", "#define LOCKWIRE_NATIVE_STUB_UDP_POSIX_H",
"#define LOCKWIRE_MAX_UDP_HANDLES 32",
],
["MOONBIT_FFI_EXPORT"],
),
)
rules.push(
source_token_rule("stub_pcap_common.c", [], ["MOONBIT_FFI_EXPORT"]),
)
rules.push(
source_token_rule("stub_frame_pool_common.c", [], ["MOONBIT_FFI_EXPORT"]),
)
rules.push(
source_token_rule("stub_npcap_windows_common.c", [], ["MOONBIT_FFI_EXPORT"]),
)
rules.push(
source_token_rule("stub_common_status.c", ["#include "], []),
)
rules.push(
source_token_rule("stub_clock_windows.c", ["QueryPerformanceCounter"], []),
)
rules.push(
source_token_rule(
"stub_clock_posix.c",
[
"#if defined(CLOCK_MONOTONIC_RAW)", "#elif defined(CLOCK_MONOTONIC)", "clock_gettime",
],
[],
),
)
rules.push(
source_token_rule(
"stub_clock_unsupported.c",
["high resolution clock unavailable"],
[],
),
)
rules
}
///|
pub fn native_stub_expected_source_token_facts() -> Array[
NativeStubSourceTokenFact,
] {
let facts : Array[NativeStubSourceTokenFact] = []
for rule in native_stub_source_token_rules() {
for token in rule.required_tokens {
facts.push(source_token_fact(rule.file, token, true))
}
for token in rule.forbidden_tokens {
facts.push(source_token_fact(rule.file, token, false))
}
}
facts
}
///|
pub fn native_stub_source_token_policy_report(
actual : Array[NativeStubSourceTokenFact],
) -> NativeStubSourceTokenPolicyReport {
native_stub_source_token_policy_report_from_rules(
native_stub_source_token_rules(),
actual,
)
}
///|
pub fn native_stub_source_token_policy_report_from_rules(
rules : Array[NativeStubSourceTokenRule],
actual : Array[NativeStubSourceTokenFact],
) -> NativeStubSourceTokenPolicyReport {
{
rule_count: rules.length(),
actual_file_count: count_actual_source_token_files(actual),
missing_file_count: count_missing_source_token_files(rules, actual),
extra_file_count: count_extra_source_token_files(rules, actual),
required_token_count: count_required_source_tokens(rules),
forbidden_token_count: count_forbidden_source_tokens(rules),
missing_required_token_count: count_missing_required_source_tokens(
rules, actual,
),
present_forbidden_token_count: count_present_forbidden_source_tokens(
rules, actual,
),
unexpected_token_fact_count: count_unexpected_source_token_facts(
rules, actual,
),
duplicate_token_fact_count: count_duplicate_source_token_facts(actual),
replaces_file_reading: false,
replaces_token_extraction: false,
live_io_evidence: false,
}
}
///|
fn source_token_rule(
file : String,
required_tokens : Array[String],
forbidden_tokens : Array[String],
) -> NativeStubSourceTokenRule {
{ file, required_tokens, forbidden_tokens }
}
///|
fn source_token_fact(
file : String,
token : String,
present : Bool,
) -> NativeStubSourceTokenFact {
{ file, token, present }
}
///|
fn count_actual_source_token_files(
facts : Array[NativeStubSourceTokenFact],
) -> Int {
let files : Array[String] = []
for fact in facts {
if !source_token_contains_string(files, fact.file) {
files.push(fact.file)
}
}
files.length()
}
///|
fn count_missing_source_token_files(
rules : Array[NativeStubSourceTokenRule],
actual : Array[NativeStubSourceTokenFact],
) -> Int {
let mut count = 0
for rule in rules {
if !source_token_contains_file(actual, rule.file) {
count += 1
}
}
count
}
///|
fn count_extra_source_token_files(
rules : Array[NativeStubSourceTokenRule],
actual : Array[NativeStubSourceTokenFact],
) -> Int {
let seen : Array[String] = []
let mut count = 0
for fact in actual {
if !source_token_contains_string(seen, fact.file) {
seen.push(fact.file)
if !source_token_contains_rule_file(rules, fact.file) {
count += 1
}
}
}
count
}
///|
fn count_required_source_tokens(
rules : Array[NativeStubSourceTokenRule],
) -> Int {
let mut count = 0
for rule in rules {
count += rule.required_tokens.length()
}
count
}
///|
fn count_forbidden_source_tokens(
rules : Array[NativeStubSourceTokenRule],
) -> Int {
let mut count = 0
for rule in rules {
count += rule.forbidden_tokens.length()
}
count
}
///|
fn count_missing_required_source_tokens(
rules : Array[NativeStubSourceTokenRule],
actual : Array[NativeStubSourceTokenFact],
) -> Int {
let mut count = 0
for rule in rules {
for token in rule.required_tokens {
if !source_token_contains_present_fact(actual, rule.file, token) {
count += 1
}
}
}
count
}
///|
fn count_present_forbidden_source_tokens(
rules : Array[NativeStubSourceTokenRule],
actual : Array[NativeStubSourceTokenFact],
) -> Int {
let mut count = 0
for rule in rules {
for token in rule.forbidden_tokens {
if source_token_contains_present_fact(actual, rule.file, token) {
count += 1
}
}
}
count
}
///|
fn count_unexpected_source_token_facts(
rules : Array[NativeStubSourceTokenRule],
actual : Array[NativeStubSourceTokenFact],
) -> Int {
let mut count = 0
for fact in actual {
if !source_token_rule_allows_fact(rules, fact.file, fact.token) {
count += 1
}
}
count
}
///|
fn count_duplicate_source_token_facts(
facts : Array[NativeStubSourceTokenFact],
) -> Int {
let seen : Array[NativeStubSourceTokenFact] = []
let mut count = 0
for fact in facts {
if source_token_contains_file_token(seen, fact.file, fact.token) {
count += 1
} else {
seen.push(fact)
}
}
count
}
///|
fn source_token_rule_allows_fact(
rules : Array[NativeStubSourceTokenRule],
file : String,
token : String,
) -> Bool {
for rule in rules {
if rule.file == file &&
(
source_token_contains_string(rule.required_tokens, token) ||
source_token_contains_string(rule.forbidden_tokens, token)
) {
return true
}
}
false
}
///|
fn source_token_contains_rule_file(
rules : Array[NativeStubSourceTokenRule],
file : String,
) -> Bool {
for rule in rules {
if rule.file == file {
return true
}
}
false
}
///|
fn source_token_contains_file(
facts : Array[NativeStubSourceTokenFact],
file : String,
) -> Bool {
for fact in facts {
if fact.file == file {
return true
}
}
false
}
///|
fn source_token_contains_present_fact(
facts : Array[NativeStubSourceTokenFact],
file : String,
token : String,
) -> Bool {
for fact in facts {
if fact.file == file && fact.token == token && fact.present {
return true
}
}
false
}
///|
fn source_token_contains_file_token(
facts : Array[NativeStubSourceTokenFact],
file : String,
token : String,
) -> Bool {
for got in facts {
if got.file == file && got.token == token {
return true
}
}
false
}
///|
fn source_token_contains_string(items : Array[String], item : String) -> Bool {
for got in items {
if got == item {
return true
}
}
false
}