diff --git a/codegenerator/rust_tui.py b/codegenerator/rust_tui.py
index b2ccb87..5c732c4 100644
--- a/codegenerator/rust_tui.py
+++ b/codegenerator/rust_tui.py
@@ -20,11 +20,24 @@ from codegenerator.base import BaseGenerator
from codegenerator import common
from codegenerator import model
from codegenerator.common import BaseCompoundType
+from codegenerator.common import BaseCombinedType
+from codegenerator.common import BasePrimitiveType
from codegenerator.common import rust as common_rust
from codegenerator.rust_sdk import TypeManager as SdkTypeManager
from codegenerator import rust_sdk
+BASIC_FIELDS = [
+ "name",
+ "title",
+ "created_at",
+ "updated_at",
+ "state",
+ "status",
+ "operating_status",
+]
+
+
class String(common_rust.String):
type_hint: str = "String"
@@ -172,6 +185,83 @@ class Struct(rust_sdk.Struct):
return result
+class StructFieldResponse(common_rust.StructField):
+ """Response Structure Field"""
+
+ @property
+ def type_hint(self):
+ typ_hint = self.data_type.type_hint
+ if self.is_optional and not typ_hint.startswith("Option<"):
+ typ_hint = f"Option<{typ_hint}>"
+ return typ_hint
+
+ @property
+ def serde_macros(self):
+ macros = set()
+ if self.local_name != self.remote_name:
+ macros.add(f'rename="{self.remote_name}"')
+ if self.is_optional or self.data_type.type_hint.startswith("Option<"):
+ macros.add("default")
+ return f"#[serde({', '.join(sorted(macros))})]"
+
+ def get_structable_macros(
+ self,
+ struct: "StructResponse",
+ service_name: str,
+ resource_name: str,
+ operation_type: str,
+ ):
+ macros = set()
+ if self.is_optional or self.data_type.type_hint.startswith("Option<"):
+ macros.add("optional")
+ macros.add(f'title="{self.remote_name.upper()}"')
+ # Fully Qualified Attribute Name
+ fqan: str = ".".join(
+ [service_name, resource_name, self.remote_name]
+ ).lower()
+ # Check the known alias of the field by FQAN
+ alias = common.FQAN_ALIAS_MAP.get(fqan)
+ if operation_type in ["list", "list_from_struct"]:
+ if (
+ "id" in struct.fields.keys()
+ and not (
+ self.local_name in BASIC_FIELDS or alias in BASIC_FIELDS
+ )
+ ) or (
+ "id" not in struct.fields.keys()
+ and (self.local_name not in list(struct.fields.keys())[-10:])
+ and not (
+ self.local_name in BASIC_FIELDS or alias in BASIC_FIELDS
+ )
+ ):
+ # Only add "wide" flag if field is not in the basic fields AND
+ # there is at least "id" field existing in the struct OR the
+ # field is not in the first 10
+ macros.add("wide")
+ if (
+ self.local_name == "state"
+ and "status" not in struct.fields.keys()
+ ):
+ macros.add("status")
+ elif (
+ self.local_name == "operating_status"
+ and "status" not in struct.fields.keys()
+ ):
+ macros.add("status")
+ return f"#[structable({', '.join(sorted(macros))})]"
+
+
+class StructResponse(common_rust.Struct):
+ field_type_class_: Type[common_rust.StructField] = StructFieldResponse
+
+ @property
+ def imports(self):
+ imports: set[str] = {"serde::Deserialize"}
+ for field in self.fields.values():
+ imports.update(field.data_type.imports)
+ return imports
+
+
class TypeManager(common_rust.TypeManager):
"""Rust SDK type manager
@@ -241,6 +331,112 @@ class TypeManager(common_rust.TypeManager):
yield (v.item_type, sdk_type)
+class ResponseTypeManager(common_rust.TypeManager):
+ primitive_type_mapping: dict[
+ Type[model.PrimitiveType], Type[BasePrimitiveType]
+ ] = {
+ model.PrimitiveString: common_rust.String,
+ model.ConstraintString: common_rust.String,
+ }
+
+ data_type_mapping = {
+ model.Struct: StructResponse,
+ model.Array: common_rust.JsonValue,
+ model.Dictionary: common_rust.JsonValue,
+ }
+
+ def get_model_name(self, model_ref: model.Reference | None) -> str:
+ """Get the localized model type name
+
+ In order to avoid collision between structures in request and
+ response we prefix all types with `Response`
+ :returns str: Type name
+ """
+ if not model_ref:
+ return "Response"
+ return "Response" + "".join(
+ x.capitalize()
+ for x in re.split(common.SPLIT_NAME_RE, model_ref.name)
+ )
+
+ def _get_struct_type(self, type_model: model.Struct) -> common_rust.Struct:
+ """Convert model.Struct into Rust `Struct`"""
+ struct_class = self.data_type_mapping[model.Struct]
+ mod = struct_class(
+ name=self.get_model_name(type_model.reference),
+ description=common_rust.sanitize_rust_docstrings(
+ type_model.description
+ ),
+ )
+ field_class = mod.field_type_class_
+ for field_name, field in type_model.fields.items():
+ is_nullable: bool = False
+ field_data_type = self.convert_model(field.data_type)
+ if isinstance(field_data_type, self.option_type_class):
+ # Unwrap Option into "is_nullable" NOTE: but perhaps
+ # Option