///|
pub(all) suberror GedError {
Syntax(Int32, String)
Limit(String)
InvalidState(String)
Query(String)
} derive(@debug.Debug)
///|
/// Empty and a void pointer are distinct. Text beginning with @ is unescaped.
pub(all) enum Payload {
Empty
Text(String)
Pointer(String)
Void
} derive(Eq, @debug.Debug)
///|
pub extend GedError with @debug.Debug::{to_repr}
///|
pub extend Payload with @debug.Debug::{to_repr}
///|
pub extend Payload with Eq::{equal, not_equal}
///|
/// A preorder node. parent is an index in the owning Document.
pub struct Node {
line : Int32
level : Int32
xref : String?
tag : String
payload : Payload
parent : Int32?
} derive(Eq, @debug.Debug)
///|
pub extend Node with @debug.Debug::{to_repr}
///|
pub extend Node with Eq::{equal, not_equal}
///|
pub struct Document {
priv nodes : Array[Node]
priv records : Array[Int32]
priv ids : Map[String, Int32]
}
///|
/// Return a copy so callers cannot corrupt indices by editing an array.
pub fn Document::nodes(self : Document) -> Array[Node] {
self.nodes.copy()
}
///|
pub fn Document::record_indices(self : Document) -> Array[Int32] {
self.records.copy()
}
///|
pub fn Document::length(self : Document) -> Int32 {
self.nodes.length()
}
///|
pub fn Document::node(self : Document, index : Int32) -> Node? {
if index < 0 || index >= self.nodes.length() {
None
} else {
Some(self.nodes[index])
}
}
///|
/// Identifiers omit their surrounding @ delimiters.
pub fn Document::lookup(self : Document, id : String) -> Int32? {
self.ids.get(id)
}
///|
pub fn Document::children(self : Document, index : Int32) -> Array[Int32] {
let out = []
if index < 0 || index >= self.nodes.length() {
return out
}
let level = self.nodes[index].level
for i = index + 1; i < self.nodes.length(); i = i + 1 {
if self.nodes[i].level <= level {
break
}
if self.nodes[i].parent == Some(index) {
out.push(i)
}
}
out
}
///|
pub fn Document::select(
self : Document,
parent : Int32,
tag : String,
) -> Array[Int32] {
self.children(parent).filter(fn(i) { self.nodes[i].tag == tag })
}
///|
pub fn Document::first(self : Document, parent : Int32, tag : String) -> Int32? {
self.select(parent, tag).get(0)
}
///|
pub fn Payload::text(self : Payload) -> String? {
match self {
Text(s) => Some(s)
_ => None
}
}
///|
pub fn Payload::target(self : Payload) -> String? {
match self {
Pointer(s) => Some(s)
_ => None
}
}