@@[target("rust")]

// Frame type string → Rust storage-type spelling.
//
// Frame has NO type system: type names are passed through to the
// generated code VERBATIM (docs/frame_language.md). Write your target
// language's own type names (`i64`, `String`, `Vec<i32>`, `MyType`) — this
// mapper does NOT translate `int`→`i64`, `str`→`String`, etc. (that
// alias table was removed; it contradicted the passthrough contract).
//
// The two transforms that REMAIN are ownership-widening, not name
// aliasing: a borrowed param type that has to be stored *owned* inside a
// generated struct (XContext, event variant, return-enum variant) widens
// `&str` → `String` and `&[T]` → `Vec<T>`. The call boundary keeps the
// borrowed signature (see rust_owned_promotion + the dispatch site in
// rust_system.rs); this fires only where the value is stored owned. This
// is correctness, not convenience — and framec's own dogfooded `.frs`
// FSMs rely on it (they take `&str` / `&[&str]` params).
//
// `Type::Unknown` (no annotation) arrives as "" and maps to `String` — a
// safe owned default where a concrete type is required.
//
// Single match expression at the end so the body's one `@@:(...)` call
// wins. (See swift_map_type.frs for the observation that Frame's
// @@:(value) sets the return value rather than returning early.)

@@system RustMapType {
    interface:
        map(t: String): String

    machine:
        $Active {
            map(t: String): String {
                let result = if t.is_empty() {
                    "String".to_string()
                } else if t == "&str" {
                    "String".to_string()
                } else if t.starts_with("&[") && t.ends_with(']') {
                    let inner = &t[2..t.len() - 1];
                    format!("Vec<{}>", inner)
                } else {
                    t
                };
                @@:(result)
            }
        }
}
