///|
/// An immutable, canonical declaration identity.
///
/// Keys compare their complete encoded bytes. Hashing is only an acceleration
/// used by hashed containers before exact equality; it is not identity.
pub struct DeclarationKey {
priv bytes : Bytes
} derive(Eq, Hash, Debug)
///|
/// Cache behavior for one declaration channel.
pub(all) enum DeclarationChannel {
/// The channel never changes for a reused view identity.
Constant
/// The channel changes exactly when its canonical key changes.
Exact(DeclarationKey)
/// The channel must be treated as changed on every reconciliation.
Uncacheable
} derive(Eq)
///|
/// The four independently declared invalidation channels for a view node.
pub struct ViewDeclaration {
layout : DeclarationChannel
paint : DeclarationChannel
semantics : DeclarationChannel
platform : DeclarationChannel
} derive(Eq)
///|
/// Effective changes between two declarations.
///
/// A layout change always implies paint, semantics, and platform changes.
pub struct DeclarationChanges {
layout : Bool
paint : Bool
semantics : Bool
platform : Bool
} derive(Eq, Debug)
///|
fn declaration_key_frame(tag : Byte, payload : Bytes) -> DeclarationKey {
let output = Buffer(size_hint=1 + 8 + payload.length())
output.write_byte(tag)
output.write_uint64_be(payload.length().to_uint64())
output.write_bytes(payload)
{ bytes: output.to_bytes() }
}
///|
fn declaration_key_write_framed(output : Buffer, value : Bytes) -> Unit {
output.write_uint64_be(value.length().to_uint64())
output.write_bytes(value)
}
///|
/// Builds a key for a boolean value.
pub fn DeclarationKey::bool(value : Bool) -> DeclarationKey {
declaration_key_frame(1, if value { b"\x01" } else { b"\x00" })
}
///|
/// Builds a key for an exact signed 32-bit `Int` value.
pub fn DeclarationKey::int(value : Int) -> DeclarationKey {
let payload = Buffer(size_hint=4)
payload.write_int_be(value)
declaration_key_frame(2, payload.to_bytes())
}
///|
/// Builds a key for an exact unsigned 32-bit `UInt` value.
pub fn DeclarationKey::uint(value : UInt) -> DeclarationKey {
let payload = Buffer(size_hint=4)
payload.write_uint_be(value)
declaration_key_frame(3, payload.to_bytes())
}
///|
/// Builds a key for an exact signed 64-bit integer value.
pub fn DeclarationKey::int64(value : Int64) -> DeclarationKey {
let payload = Buffer(size_hint=8)
payload.write_int64_be(value)
declaration_key_frame(4, payload.to_bytes())
}
///|
/// Builds a key for an exact unsigned 64-bit integer value.
pub fn DeclarationKey::uint64(value : UInt64) -> DeclarationKey {
declaration_key_frame(5, value.to_be_bytes())
}
///|
/// Builds a bit-exact IEEE-754 key. This distinguishes signed zero and NaN
/// payloads as well as adjacent finite values.
pub fn DeclarationKey::double(value : Double) -> DeclarationKey {
declaration_key_frame(6, value.reinterpret_as_uint64().to_be_bytes())
}
///|
/// Builds a key from the value's exact UTF-8 encoding without a BOM.
pub fn DeclarationKey::string(value : String) -> DeclarationKey {
declaration_key_frame(7, @utf8.encode(value[:], bom=false))
}
///|
/// Builds a key from immutable bytes.
pub fn DeclarationKey::bytes(value : Bytes) -> DeclarationKey {
declaration_key_frame(8, value)
}
///|
/// Builds an option key. Presence and the complete child key are framed.
pub fn DeclarationKey::option(value : DeclarationKey?) -> DeclarationKey {
let payload = Buffer()
match value {
None => payload.write_byte(0)
Some(value) => {
payload.write_byte(1)
declaration_key_write_framed(payload, value.bytes)
}
}
declaration_key_frame(9, payload.to_bytes())
}
///|
/// Builds an ordered array key from complete child keys.
pub fn DeclarationKey::array(values : Array[DeclarationKey]) -> DeclarationKey {
let payload = Buffer()
payload.write_uint64_be(values.length().to_uint64())
for value in values {
declaration_key_write_framed(payload, value.bytes)
}
declaration_key_frame(10, payload.to_bytes())
}
///|
/// Builds a record key. `type_tag` identifies the declared record type;
/// fields are encoded in the supplied declaration order, including each field
/// name and complete child key.
pub fn DeclarationKey::record(
type_tag~ : String,
fields~ : Array[(String, DeclarationKey)],
) -> DeclarationKey {
let payload = Buffer()
declaration_key_write_framed(payload, @utf8.encode(type_tag[:], bom=false))
payload.write_uint64_be(fields.length().to_uint64())
for field in fields {
declaration_key_write_framed(payload, @utf8.encode(field.0[:], bom=false))
declaration_key_write_framed(payload, field.1.bytes)
}
declaration_key_frame(11, payload.to_bytes())
}
///|
/// Declares four channels that remain constant for a reused view identity.
pub fn ViewDeclaration::constant() -> ViewDeclaration {
ViewDeclaration::channels(
layout=Constant,
paint=Constant,
semantics=Constant,
platform=Constant,
)
}
///|
/// Declares four channels that must be recomputed on every reconciliation.
pub fn ViewDeclaration::uncacheable() -> ViewDeclaration {
ViewDeclaration::channels(
layout=Uncacheable,
paint=Uncacheable,
semantics=Uncacheable,
platform=Uncacheable,
)
}
///|
/// Declares cache behavior independently for all four channels.
pub fn ViewDeclaration::channels(
layout~ : DeclarationChannel,
paint~ : DeclarationChannel,
semantics~ : DeclarationChannel,
platform~ : DeclarationChannel,
) -> ViewDeclaration {
{ layout, paint, semantics, platform }
}
///|
pub fn ViewDeclaration::layout(self : ViewDeclaration) -> DeclarationChannel {
self.layout
}
///|
pub fn ViewDeclaration::paint(self : ViewDeclaration) -> DeclarationChannel {
self.paint
}
///|
pub fn ViewDeclaration::semantics(self : ViewDeclaration) -> DeclarationChannel {
self.semantics
}
///|
pub fn ViewDeclaration::platform(self : ViewDeclaration) -> DeclarationChannel {
self.platform
}
///|
fn DeclarationChannel::changed_from(
self : DeclarationChannel,
previous : DeclarationChannel,
) -> Bool {
match (self, previous) {
(Constant, Constant) => false
(Exact(current), Exact(previous)) => current != previous
_ => true
}
}
///|
/// Classifies effective invalidation from `previous` to this declaration.
pub fn ViewDeclaration::changes_from(
self : ViewDeclaration,
previous : ViewDeclaration,
) -> DeclarationChanges {
let layout = self.layout.changed_from(previous.layout)
{
layout,
paint: layout || self.paint.changed_from(previous.paint),
semantics: layout || self.semantics.changed_from(previous.semantics),
platform: layout || self.platform.changed_from(previous.platform),
}
}
///|
pub fn DeclarationChanges::layout(self : DeclarationChanges) -> Bool {
self.layout
}
///|
pub fn DeclarationChanges::paint(self : DeclarationChanges) -> Bool {
self.paint
}
///|
pub fn DeclarationChanges::semantics(self : DeclarationChanges) -> Bool {
self.semantics
}
///|
pub fn DeclarationChanges::platform(self : DeclarationChanges) -> Bool {
self.platform
}
///|
pub fn DeclarationChanges::is_clean(self : DeclarationChanges) -> Bool {
!self.layout && !self.paint && !self.semantics && !self.platform
}