///|
/// Shared-type metadata used by update codecs. XmlHook and Undefined preserve
/// legacy/untyped descriptors even when no concrete collection handle exists.
pub(all) enum TypeRef {
Array
Map
Text
XmlElement(String)
XmlFragment
XmlHook
XmlText
WeakLink(LinkSource)
SubDoc
Undefined
} derive(Eq, Debug)
///|
pub fn TypeRef::kind(self : TypeRef) -> Byte {
(match self {
Array => 0
Map => 1
Text => 2
XmlElement(_) => 3
XmlFragment => 4
XmlHook => 5
XmlText => 6
WeakLink(_) => 7
SubDoc => 9
Undefined => 15
}).to_byte()
}
///|
/// Primitive values have no shared-type descriptor.
pub fn Out::type_ref(self : Out) -> TypeRef? {
Some(
match self {
Value(_) => return None
Array(_) => Array
Map(_) => Map
Text(_) => Text
XmlElement(value) => XmlElement(value.tag())
XmlFragment(_) => XmlFragment
XmlText(_) => XmlText
WeakLink(value) => WeakLink(value.source())
Subdoc(_) => SubDoc
UndefinedRef(value) =>
match value.type_ref() {
5 => XmlHook
9 => SubDoc
_ => Undefined
}
},
)
}
///|
pub impl Encode for TypeRef with fn encode(self, encoder) {
encoder.write_type_ref(self.kind())
match self {
XmlElement(name) => encoder.write_key(name)
WeakLink(link) => {
let single = link.is_single()
let mut flags = if single { 0 } else { 1 }
if link.start.assoc == After {
flags = flags | 2
}
if link.end.assoc == After {
flags = flags | 4
}
if !link.start.is_relative() {
flags = flags | 8
}
if !link.end.is_relative() {
flags = flags | 16
}
if link.start.is_root() || link.end.is_root() {
flags = flags | 32
}
Write::write_u8(encoder, flags.to_byte())
fn scope(index : StickyIndex) -> Unit {
match index.scope {
Root(name) => Write::write_string(encoder, name)
Relative(id) | Nested(id) => {
Write::write_var_uint(encoder, id.client)
Write::write_var_uint(encoder, id.clock.to_uint64())
}
}
}
scope(link.start)
if !single || !link.end.is_relative() {
scope(link.end)
}
}
_ => ()
}
}
///|
pub impl Decode for TypeRef with fn decode(decoder) {
match decoder.read_type_ref().to_int() {
0 => Array
1 => Map
2 => Text
3 => XmlElement(decoder.read_key())
4 => XmlFragment
5 => XmlHook
6 => XmlText
7 => {
let flags = Read::read_u8(decoder).to_int()
guard flags < 64 else { raise InvalidData("invalid weak link flags") }
fn scope(unbounded : Bool) -> IndexScope raise DecodeError {
if unbounded && (flags & 32) != 0 {
Root(Read::read_string(decoder))
} else {
let id : Id = {
client: Read::read_var_uint(decoder),
clock: codec_clock(Read::read_var_uint(decoder)),
}
if unbounded {
Nested(id)
} else {
Relative(id)
}
}
}
let start = scope((flags & 8) != 0)
let end = if (flags & 16) != 0 {
scope(true)
} else if (flags & 1) == 0 {
start
} else {
scope(false)
}
WeakLink(
LinkSource(
StickyIndex(
scope=start,
assoc=if (flags & 2) != 0 { After } else { Before },
),
StickyIndex(
scope=end,
assoc=if (flags & 4) != 0 { After } else { Before },
),
),
)
}
9 => SubDoc
15 => Undefined
_ => raise InvalidData("unsupported shared type reference")
}
}
///|
pub extend TypeRef with Eq::{equal, not_equal}
///|
pub extend TypeRef with Debug::{to_repr}
///|
pub extend TypeRef with Encode::{encode, encode_v1, encode_v2}
///|
pub extend TypeRef with Decode::{decode, decode_v1, decode_v2}