// Copyright 2026 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.
let feat_flag_exclusive = 0x8000
let feat_flag_not_default = 0x4000
let feat_flag_index_mask = 0x00ff
///|
/// Feature setting name record.
pub struct FeatSettingName {
setting : Int
name_id : Int
} derive(Eq, Show, ToJson)
///|
/// Feature name record.
pub struct FeatFeatureName {
feature : Int
name_id : Int
flags : Int
settings : Array[FeatSettingName]
} derive(Eq, Show, ToJson)
///|
/// Parsed feat table.
pub struct FeatTable {
version : Int
features : Array[FeatFeatureName]
} derive(Show, ToJson)
///|
pub fn FeatTable::has_data(self : FeatTable) -> Bool {
self.version != 0
}
///|
pub fn FeatTable::feature_types(self : FeatTable) -> Array[Int] {
let types : Array[Int] = []
for feature in self.features {
types.push(feature.feature)
}
types
}
///|
pub fn FeatTable::feature(
self : FeatTable,
feature_type : Int,
) -> FeatFeatureName? {
for feature in self.features {
if feature.feature == feature_type {
return Some(feature)
}
}
None
}
///|
pub fn FeatFeatureName::is_exclusive(self : FeatFeatureName) -> Bool {
(self.flags & feat_flag_exclusive) != 0
}
///|
pub fn FeatFeatureName::default_setting_index(
self : FeatFeatureName,
) -> Int? {
if !self.is_exclusive() {
return None
}
let index = if (self.flags & feat_flag_not_default) != 0 {
self.flags & feat_flag_index_mask
} else {
0
}
if index < 0 || index >= self.settings.length() {
None
} else {
Some(index)
}
}
///|
pub fn FeatFeatureName::default_setting(
self : FeatFeatureName,
) -> FeatSettingName? {
match self.default_setting_index() {
None => None
Some(index) => Some(self.settings[index])
}
}
///|
/// Parse a feat table.
pub fn FeatTable::parse(data : BytesView) -> Result[FeatTable, AatError] {
let version = read_i32(data, 0)
let feature_count = read_u16_int(data, 4)
let reserved1 = read_u16_int(data, 6)
let reserved2 = read_u32_non_negative(data, 8)
match (version, feature_count, reserved1, reserved2) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(version), Ok(feature_count), Ok(_), Ok(_)) => {
if feature_count < 0 {
return Err(InvalidFormat)
}
let records_base = 12
let record_size = 12
if records_base + feature_count * record_size > data.length() {
return Err(UnexpectedEof)
}
let features : Array[FeatFeatureName] = []
for i in 0.. return Err(err)
(_, Err(err), _, _, _) => return Err(err)
(_, _, Err(err), _, _) => return Err(err)
(_, _, _, Err(err), _) => return Err(err)
(_, _, _, _, Err(err)) => return Err(err)
(Ok(feature), Ok(n_settings), Ok(settings_offset), Ok(flags), Ok(name_id)) => {
if n_settings < 0 || settings_offset < 0 {
return Err(InvalidFormat)
}
if settings_offset + n_settings * 4 > data.length() {
return Err(UnexpectedEof)
}
let settings : Array[FeatSettingName] = []
for j in 0.. return Err(err)
(_, Err(err)) => return Err(err)
(Ok(setting), Ok(setting_name)) => {
settings.push(
FeatSettingName::{ setting, name_id: setting_name },
)
}
}
}
features.push(
FeatFeatureName::{ feature, name_id, flags, settings },
)
}
}
}
Ok(FeatTable::{ version, features })
}
}
}