Skip to main content

unity_solution_generator/
xml.rs

1/// XML-escape a value for an attribute or text node. Matches the five
2/// substitutions used by the Swift generator (`&`, `"`, `<`, `>`, `'`).
3pub fn xml_escape(value: &str) -> String {
4    let mut out = String::with_capacity(value.len());
5    for ch in value.chars() {
6        match ch {
7            '&' => out.push_str("&amp;"),
8            '"' => out.push_str("&quot;"),
9            '<' => out.push_str("&lt;"),
10            '>' => out.push_str("&gt;"),
11            '\'' => out.push_str("&apos;"),
12            _ => out.push(ch),
13        }
14    }
15    out
16}
17
18/// Stable GUID derived from a project name. Mirrors the Swift djb2/fnv-1a
19/// blend so generated `.csproj`/`.sln` GUIDs are byte-identical between
20/// runtimes — same project name → same GUID.
21pub fn deterministic_guid(name: &str) -> String {
22    let mut h1: u64 = 5381;
23    let mut h2: u64 = 0xcbf29ce484222325;
24    for &b in name.as_bytes() {
25        h1 = h1.wrapping_shl(5).wrapping_add(h1).wrapping_add(b as u64);
26        h2 = (h2 ^ b as u64).wrapping_mul(0x100000001b3);
27    }
28    let p1 = (h1 >> 32) & 0xFFFF_FFFF;
29    let p2 = (h1 >> 16) & 0xFFFF;
30    let p3 = h1 & 0xFFFF;
31    let p4 = (h2 >> 48) & 0xFFFF;
32    let p5 = (h2 >> 32) & 0xFFFF;
33    let p6 = h2 & 0xFFFF_FFFF;
34    format!(
35        "{{{:08X}-{:04X}-{:04X}-{:04X}-{:04X}{:08X}}}",
36        p1, p2, p3, p4, p5, p6
37    )
38}