use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub enum AttrType {
Enumeration,
String,
Integer,
Boolean,
Password,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegistryAttribute {
pub name: String,
pub display_name: String,
pub description: String,
pub attr_type: AttrType,
pub current_value: Option<Value>,
pub pending_value: Option<Value>,
pub default_value: Option<Value>,
pub allowed_values: Option<Vec<AllowedValue>>,
pub lower_bound: Option<i64>,
pub upper_bound: Option<i64>,
pub min_length: Option<u64>,
pub max_length: Option<u64>,
pub read_only: bool,
pub hidden: bool,
pub group: Option<String>,
pub display_order: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllowedValue {
pub value: String,
pub display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegistryMessage {
pub message_id: String,
pub description: String,
pub message: String,
pub severity: Option<String>,
pub number_of_args: Option<u32>,
pub resolution: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegistryInfo {
pub registry_id: String,
pub name: String,
pub description: Option<String>,
pub registry_version: Option<String>,
pub owning_entity: Option<String>,
}
pub fn parse_bios_registry(
registry_json: &Value,
current_attrs: Option<&Value>,
pending_attrs: Option<&Value>,
) -> Vec<RegistryAttribute> {
let entries = registry_json
.pointer("/RegistryEntries/Attributes")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default();
entries
.iter()
.filter_map(|entry| parse_attribute_entry(entry, current_attrs, pending_attrs))
.collect()
}
pub fn parse_attribute_registry(
registry_json: &Value,
current_attrs: Option<&Value>,
) -> Vec<RegistryAttribute> {
let entries = registry_json
.pointer("/RegistryEntries/Attributes")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default();
entries
.iter()
.filter_map(|entry| parse_attribute_entry(entry, current_attrs, None))
.collect()
}
pub fn parse_message_registry(registry_json: &Value) -> (RegistryInfo, Vec<RegistryMessage>) {
let info = RegistryInfo {
registry_id: registry_json
.get("Id")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string(),
name: registry_json
.get("Name")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string(),
description: registry_json.get("Description").and_then(|v| v.as_str()).map(String::from),
registry_version: registry_json
.get("RegistryVersion")
.and_then(|v| v.as_str())
.map(String::from),
owning_entity: registry_json
.get("OwningEntity")
.and_then(|v| v.as_str())
.map(String::from),
};
let messages = registry_json
.get("Messages")
.and_then(|v| v.as_object())
.map(|obj| {
obj.iter()
.map(|(key, val)| RegistryMessage {
message_id: key.clone(),
description: val
.get("Description")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string(),
message: val
.get("Message")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string(),
severity: val.get("Severity").and_then(|v| v.as_str()).map(String::from),
number_of_args: val
.get("NumberOfArgs")
.and_then(|v| v.as_u64())
.map(|n| n as u32),
resolution: val.get("Resolution").and_then(|v| v.as_str()).map(String::from),
})
.collect()
})
.unwrap_or_default();
(info, messages)
}
fn parse_attribute_entry(
entry: &Value,
current_attrs: Option<&Value>,
pending_attrs: Option<&Value>,
) -> Option<RegistryAttribute> {
let name = entry.get("AttributeName").and_then(|v| v.as_str())?;
let attr_type = match entry.get("Type").and_then(|v| v.as_str()).unwrap_or("String") {
"Enumeration" => AttrType::Enumeration,
"Integer" => AttrType::Integer,
"Boolean" => AttrType::Boolean,
"Password" => AttrType::Password,
_ => AttrType::String,
};
let allowed_values = entry.get("Value").and_then(|v| v.as_array()).map(|arr| {
arr.iter()
.filter_map(|item| {
let value = item.get("ValueName").and_then(|v| v.as_str())?;
let display_name = item
.get("ValueDisplayName")
.and_then(|v| v.as_str())
.map(String::from);
Some(AllowedValue {
value: value.to_string(),
display_name,
})
})
.collect()
});
let current_value = current_attrs.and_then(|attrs| attrs.get(name)).cloned();
let pending_value = pending_attrs.and_then(|attrs| attrs.get(name)).cloned();
Some(RegistryAttribute {
name: name.to_string(),
display_name: entry
.get("DisplayName")
.and_then(|v| v.as_str())
.unwrap_or(name)
.to_string(),
description: entry
.get("HelpText")
.or_else(|| entry.get("Description"))
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string(),
attr_type,
current_value,
pending_value,
default_value: entry.get("DefaultValue").cloned(),
allowed_values,
lower_bound: entry.get("LowerBound").and_then(|v| v.as_i64()),
upper_bound: entry.get("UpperBound").and_then(|v| v.as_i64()),
min_length: entry.get("MinLength").and_then(|v| v.as_u64()),
max_length: entry.get("MaxLength").and_then(|v| v.as_u64()),
read_only: entry.get("ReadOnly").and_then(|v| v.as_bool()).unwrap_or(false),
hidden: entry.get("Hidden").and_then(|v| v.as_bool()).unwrap_or(false),
group: entry
.get("MenuPath")
.or_else(|| entry.get("GroupName"))
.and_then(|v| v.as_str())
.map(String::from),
display_order: entry.get("DisplayOrder").and_then(|v| v.as_u64()),
})
}