from typing import Dict, Optional, TYPE_CHECKING
from ..naming import convert_to_snake_case, escape_rust_keyword
from ..type_mapping import MatterType
from .tlv_helpers import (
_generate_struct_field_assignments,
_generate_list_decoder,
_generate_single_value_decoder,
)
from .field import MatterField
if TYPE_CHECKING:
from .enums import MatterEnum, MatterBitmap
from .structs import MatterStruct
class AttributeField:
def __init__(self, hex_id: str, field: MatterField):
self.hex_id = hex_id
self._field = field
@property
def id(self) -> str:
return self.hex_id
@property
def name(self) -> str:
return self._field.name
@property
def attr_type(self) -> str:
return self._field.field_type
@property
def default(self) -> Optional[str]:
return self._field.default
@property
def nullable(self) -> bool:
return self._field.nullable
@property
def entry_type(self) -> Optional[str]:
return self._field.entry_type
@property
def is_list(self) -> bool:
return self._field.is_list
def get_rust_function_name(self) -> str:
return f"decode_{escape_rust_keyword(convert_to_snake_case(self.name))}"
def get_rust_return_type(self, structs: Optional[Dict[str, 'MatterStruct']] = None, enums: Optional[Dict[str, 'MatterEnum']] = None, bitmaps: Optional[Dict[str, 'MatterBitmap']] = None) -> str:
if self.is_list:
if self.entry_type:
if structs and self.entry_type in structs:
struct_name = structs[self.entry_type].get_rust_struct_name()
return f"Vec<{struct_name}>"
else:
entry_rust_type = MatterType.get_rust_type(self.entry_type, enums=enums, bitmaps=bitmaps)
return f"Vec<{entry_rust_type}>"
else:
return "Vec<String>"
else:
if structs and self.attr_type in structs:
struct_name = structs[self.attr_type].get_rust_struct_name()
if self.nullable:
return f"Option<{struct_name}>"
return struct_name
else:
rust_type = MatterType.get_rust_type(self.attr_type, enums=enums, bitmaps=bitmaps)
if self.nullable:
return f"Option<{rust_type}>"
return rust_type
def generate_decode_function(self, structs: Optional[Dict[str, 'MatterStruct']] = None, enums: Optional[Dict[str, 'MatterEnum']] = None, bitmaps: Optional[Dict[str, 'MatterBitmap']] = None) -> str:
func_name = self.get_rust_function_name()
return_type = self.get_rust_return_type(structs, enums, bitmaps)
clean_id = self.id
if self.is_list:
if self.entry_type and structs and self.entry_type in structs:
struct = structs[self.entry_type]
struct_name = struct.get_rust_struct_name()
field_assignments = _generate_struct_field_assignments(struct.fields, structs, enums, "item", bitmaps)
assignments_str = "\n".join(field_assignments)
decode_logic = f''' let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {{
for item in v {{
res.push({struct_name} {{
{assignments_str}
}});
}}
}}
Ok(res)'''
elif self.entry_type:
decode_logic = _generate_list_decoder(self.entry_type, enums, bitmaps)
else:
decode_logic = ''' let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
if let tlv::TlvItemValue::String(s) = &item.value {
res.push(s.clone());
}
}
}
Ok(res)'''
else:
tlv_type = MatterType.get_tlv_type(self.attr_type, bitmaps=bitmaps)
if structs and self.attr_type in structs:
struct = structs[self.attr_type]
struct_name = struct.get_rust_struct_name()
field_assignments = _generate_struct_field_assignments(struct.fields, structs, enums, "item", bitmaps)
assignments_str = "\n".join(field_assignments)
if self.nullable:
decode_logic = f''' if let tlv::TlvItemValue::List(_fields) = inp {{
// Struct with fields
let item = tlv::TlvItem {{ tag: 0, value: inp.clone() }};
Ok(Some({struct_name} {{
{assignments_str}
}}))
//}} else if let tlv::TlvItemValue::Null = inp {{
// // Null value for nullable struct
// Ok(None)
}} else {{
Ok(None)
// Err(anyhow::anyhow!("Expected struct fields or null"))
}}'''
else:
decode_logic = f''' if let tlv::TlvItemValue::List(_fields) = inp {{
// Struct with fields
let item = tlv::TlvItem {{ tag: 0, value: inp.clone() }};
Ok({struct_name} {{
{assignments_str}
}})
}} else {{
Err(anyhow::anyhow!("Expected struct fields"))
}}'''
else:
decode_logic = _generate_single_value_decoder(self.attr_type, self.nullable, enums, bitmaps)
return f'''/// Decode {self.name} attribute ({clean_id})
pub fn {func_name}(inp: &tlv::TlvItemValue) -> anyhow::Result<{return_type}> {{
{decode_logic}
}}'''