neo-decompiler 0.10.1

Neo N3 NEF decompiler: parse, disassemble, lift bytecode to high-level pseudocode and C# skeletons, with a CLI, JSON reports, and optional WebAssembly bindings.
Documentation
use std::collections::HashSet;

use crate::manifest::ManifestParameter;

use super::{make_unique_identifier, sanitize_csharp_identifier};

#[derive(Clone)]
pub(in crate::decompiler::csharp) struct CSharpParameter {
    pub(in crate::decompiler::csharp) name: String,
    pub(in crate::decompiler::csharp) ty: String,
}

pub(in crate::decompiler::csharp) fn collect_csharp_parameters(
    parameters: &[ManifestParameter],
) -> Vec<CSharpParameter> {
    let mut used_names = HashSet::new();
    parameters
        .iter()
        .map(|param| CSharpParameter {
            name: make_unique_identifier(sanitize_csharp_identifier(&param.name), &mut used_names),
            ty: format_manifest_type_csharp(&param.kind, false),
        })
        .collect()
}

pub(in crate::decompiler::csharp) fn format_csharp_parameters(
    params: &[CSharpParameter],
) -> String {
    params
        .iter()
        .map(|param| format!("{} {}", param.ty, param.name))
        .collect::<Vec<_>>()
        .join(", ")
}

pub(in crate::decompiler::csharp) fn format_manifest_type_csharp(
    kind: &str,
    for_return: bool,
) -> String {
    match kind.to_ascii_lowercase().as_str() {
        // `void` is only legal in return position. In a parameter / event-arg
        // position it would render the illegal `void` / `Action<void>`
        // (C# error CS1547), so fall through to the `object` default there.
        "void" if for_return => "void".into(),
        "boolean" | "bool" => "bool".into(),
        "integer" | "int" => "BigInteger".into(),
        "string" => "string".into(),
        "hash160" => "UInt160".into(),
        "hash256" => "UInt256".into(),
        "publickey" => "ECPoint".into(),
        "bytearray" | "bytes" => "ByteString".into(),
        "signature" => "ByteString".into(),
        "array" => "object[]".into(),
        "map" => "object".into(),
        "interopinterface" => "object".into(),
        "any" => "object".into(),
        _ => "object".into(),
    }
}

pub(in crate::decompiler::csharp) fn format_method_signature(
    name: &str,
    parameters: &str,
    return_type: &str,
) -> String {
    if parameters.is_empty() {
        format!("public static {return_type} {name}()")
    } else {
        format!("public static {return_type} {name}({parameters})")
    }
}