///|
pub(all) suberror GraphError {
InvalidXml(String)
InvalidGraph(path~ : String, reason~ : String)
LimitExceeded(resource~ : String, limit~ : Int32)
Unsupported(path~ : String, feature~ : String)
} derive(Eq, @debug.Debug)
///|
pub extend GraphError with Eq::{equal, not_equal}
///|
pub extend GraphError with @debug.Debug::{to_repr}
///|
pub(all) struct Limits {
input_bytes : Int32
xml_depth : Int32
xml_elements : Int32
attributes_per_element : Int32
text_bytes : Int32
keys : Int32
graphs : Int32
nodes : Int32
edges : Int32
ports : Int32
endpoints : Int32
output_bytes : Int32
} derive(Eq, @debug.Debug)
///|
pub extend Limits with Eq::{equal, not_equal}
///|
pub extend Limits with @debug.Debug::{to_repr}
///|
pub fn Limits::default() -> Limits {
{
input_bytes: 32 * 1024 * 1024,
xml_depth: 64,
xml_elements: 1000000,
attributes_per_element: 64,
text_bytes: 4 * 1024 * 1024,
keys: 4096,
graphs: 4096,
nodes: 200000,
edges: 1000000,
ports: 1000000,
endpoints: 1000000,
output_bytes: 64 * 1024 * 1024,
}
}
///|
pub fn Limits::validate(self : Limits) -> Unit raise GraphError {
let bounds = [
("input_bytes", self.input_bytes),
("xml_depth", self.xml_depth),
("xml_elements", self.xml_elements),
("attributes_per_element", self.attributes_per_element),
("text_bytes", self.text_bytes),
("keys", self.keys),
("graphs", self.graphs),
("nodes", self.nodes),
("edges", self.edges),
("ports", self.ports),
("endpoints", self.endpoints),
("output_bytes", self.output_bytes),
]
for (resource, limit) in bounds {
if limit < 0 {
raise InvalidGraph(path="limits", reason="negative \{resource}")
}
}
if self.xml_depth > 256 {
raise InvalidGraph(path="limits", reason="xml_depth must not exceed 256")
}
}
///|
fn check_bound(
resource : String,
amount : Int32,
bound : Int32,
) -> Unit raise GraphError {
if amount < 0 || amount > bound {
raise LimitExceeded(resource~, limit=bound)
}
}
///|
fn utf8_size(text : String) -> Int32 raise GraphError {
let mut bytes = 0
let mut i = 0
while i < text.length() {
let unit = text.code_unit_at(i).to_int()
let amount = if unit < 0x80 {
1
} else if unit < 0x800 {
2
} else if unit >= 0xD800 && unit <= 0xDBFF {
require(i + 1 < text.length(), "xml.unicode", "unpaired high surrogate")
let low = text.code_unit_at(i + 1).to_int()
require(
low >= 0xDC00 && low <= 0xDFFF,
"xml.unicode",
"unpaired high surrogate",
)
i = i + 1
4
} else {
require(
unit < 0xDC00 || unit > 0xDFFF,
"xml.unicode",
"unpaired low surrogate",
)
3
}
if bytes > 2147483647 - amount {
raise LimitExceeded(resource="utf8_bytes", limit=2147483647)
}
bytes = bytes + amount
i = i + 1
}
bytes
}
///|
fn invalid(path : String, reason : String) -> Unit raise GraphError {
raise InvalidGraph(path~, reason~)
}
///|
fn require(
condition : Bool,
path : String,
reason : String,
) -> Unit raise GraphError {
if !condition {
invalid(path, reason)
}
}