use move_core_types::{
account_address::AccountAddress,
ident_str,
identifier::IdentStr,
language_storage::{StructTag, TypeTag},
};
use serde::{Deserialize, Serialize};
use crate::{IOTA_FRAMEWORK_ADDRESS, MoveTypeTagTrait, base_types::EpochId, id::UID};
pub const CONFIG_MODULE_NAME: &IdentStr = ident_str!("config");
pub const CONFIG_STRUCT_NAME: &IdentStr = ident_str!("Config");
pub const SETTING_STRUCT_NAME: &IdentStr = ident_str!("Setting");
pub const SETTING_DATA_STRUCT_NAME: &IdentStr = ident_str!("SettingData");
pub const RESOLVED_IOTA_CONFIG: (&AccountAddress, &IdentStr, &IdentStr) = (
&IOTA_FRAMEWORK_ADDRESS,
CONFIG_MODULE_NAME,
CONFIG_STRUCT_NAME,
);
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
pub id: UID,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Setting<V> {
pub data: Option<SettingData<V>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SettingData<V> {
pub newer_value_epoch: u64,
pub newer_value: Option<V>,
pub older_value_opt: Option<V>,
}
impl Config {
pub fn type_() -> StructTag {
StructTag {
address: IOTA_FRAMEWORK_ADDRESS,
module: CONFIG_MODULE_NAME.to_owned(),
name: CONFIG_STRUCT_NAME.to_owned(),
type_params: vec![],
}
}
}
pub fn setting_type(value_tag: TypeTag) -> StructTag {
StructTag {
address: IOTA_FRAMEWORK_ADDRESS,
module: CONFIG_MODULE_NAME.to_owned(),
name: SETTING_STRUCT_NAME.to_owned(),
type_params: vec![value_tag],
}
}
impl MoveTypeTagTrait for Config {
fn get_type_tag() -> TypeTag {
TypeTag::Struct(Box::new(Config::type_()))
}
}
impl<V: MoveTypeTagTrait> MoveTypeTagTrait for Setting<V> {
fn get_type_tag() -> TypeTag {
TypeTag::Struct(Box::new(setting_type(V::get_type_tag())))
}
}
pub fn is_setting(tag: &StructTag) -> bool {
let StructTag {
address,
module,
name,
type_params,
} = tag;
*address == IOTA_FRAMEWORK_ADDRESS
&& module.as_ident_str() == CONFIG_MODULE_NAME
&& name.as_ident_str() == SETTING_STRUCT_NAME
&& type_params.len() == 1
}
impl<V> Setting<V> {
pub fn read_value(&self, cur_epoch: Option<EpochId>) -> Option<&V> {
self.data.as_ref()?.read_value(cur_epoch)
}
}
impl<V> SettingData<V> {
pub fn read_value(&self, cur_epoch: Option<EpochId>) -> Option<&V> {
let use_newer_value = match cur_epoch {
Some(cur_epoch) => cur_epoch > self.newer_value_epoch,
None => true,
};
if use_newer_value {
self.newer_value.as_ref()
} else {
self.older_value_opt.as_ref()
}
}
}