// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn cache_slot(
known_dimensions : Size[Double?],
available_space : Size[AvailableSpace],
) -> Int {
let has_known_width = known_dimensions.width is Some(_)
let has_known_height = known_dimensions.height is Some(_)
if has_known_width && has_known_height {
return 0
}
if has_known_width && !has_known_height {
return 1 + (if available_space.height is AvailMinContent { 1 } else { 0 })
}
if has_known_height && !has_known_width {
return 3 + (if available_space.width is AvailMinContent { 1 } else { 0 })
}
match (available_space.width, available_space.height) {
(AvailMinContent, AvailMinContent) => 8
(AvailMinContent, _) => 7
(_, AvailMinContent) => 6
_ => 5
}
}
///|
fn find_leaf_measure_cache(
cache : Cache,
known_dimensions : Size[Double?],
available_space : Size[AvailableSpace],
run_mode : RunMode,
) -> LayoutOutput? {
if !(run_mode is ComputeSize) {
return None
}
for entry_option in cache.measure_entries {
match entry_option {
Some(entry) =>
if cache_entry_matches(
entry.known_dimensions,
entry.available_space,
LayoutOutput::from_outer_size(entry.content).outer_size(),
known_dimensions,
available_space,
) {
return Some(LayoutOutput::from_outer_size(entry.content))
}
None => ()
}
}
None
}
///|
fn store_leaf_measure_cache(
cache : Cache,
known_dimensions : Size[Double?],
available_space : Size[AvailableSpace],
run_mode : RunMode,
measured : Size[Double],
) -> Unit {
if !(run_mode is ComputeSize) {
return
}
let slot = cache_slot(known_dimensions, available_space)
cache.measure_entries[slot] = Some({
known_dimensions,
available_space,
content: measured,
})
}
///|
fn find_node_layout_cache(
cache : Cache,
known_dimensions : Size[Double?],
available_space : Size[AvailableSpace],
run_mode : RunMode,
) -> NodeLayoutCacheEntry? {
if !(run_mode is PerformLayout) {
return None
}
match cache.final_layout_entry {
Some(entry) =>
if cache_entry_matches(
entry.known_dimensions,
entry.available_space,
entry.content.outer_size(),
known_dimensions,
available_space,
) {
Some(entry)
} else {
None
}
None => None
}
}
///|
fn cache_entry_matches(
entry_known_dimensions : Size[Double?],
entry_available_space : Size[AvailableSpace],
cached_size : Size[Double],
known_dimensions : Size[Double?],
available_space : Size[AvailableSpace],
) -> Bool {
(
@util.optional_double_equal(
known_dimensions.width,
entry_known_dimensions.width,
) ||
@util.optional_double_equal(known_dimensions.width, Some(cached_size.width))
) &&
(
@util.optional_double_equal(
known_dimensions.height,
entry_known_dimensions.height,
) ||
@util.optional_double_equal(
known_dimensions.height,
Some(cached_size.height),
)
) &&
(
known_dimensions.width is Some(_) ||
@util.available_space_equal(
entry_available_space.width,
available_space.width,
)
) &&
(
known_dimensions.height is Some(_) ||
@util.available_space_equal(
entry_available_space.height,
available_space.height,
)
)
}
///|
fn store_node_layout_cache(
cache : Cache,
run_mode : RunMode,
entry : NodeLayoutCacheEntry,
) -> Unit {
if !(run_mode is PerformLayout) {
return
}
cache.final_layout_entry = Some(entry)
}
///|
fn Cache::clear(self : Cache) -> Unit {
self.final_layout_entry = None
for i in 0..