Search code examples
javascriptrustserdetauri

Sending a map from JS to Rust does not arrive


I have a small tauri app that on the JS part sends some data back to the rust backend using the invoke method.

The method works, most of the data arrives to the backend. The data itself contains a map, which does not arrive though.

const [details, setDetails] = useState({
    name: "",
    country: "",
    address: "",
    items: new Map<String, number>
})
...
async function handleSubmit(e: any) {
    e.preventDefault()
    console.log(details)
    await invoke('submit_new_customer', { details }).then((submitted) => { ... })
}

The logged out details:

{
    name: "Alfred Gustavsson",
    country: "Norway",
    address: "Exapmle street",
    items: Map(1) {'3' => 1}
}

The backend:

#[derive(Serialize, Deserialize, Debug)]
struct NewCustomerInput {
    name: String,
    country: String,
    address: Option<String>,
    items: HashMap<String, usize>
}

#[tauri::command]
fn submit_new_customer(details: NewCustomerInput) -> bool {
    println!("{:?}", details);
    ...

From the print I can see that the items is {}. How can I setup my struct to accept the Map from the fronted?


Solution

  • As mentioned in the comments, you will need to convert your Map into an Object, prior to sending:

    const mapToObj = (map) => Object.fromEntries([...map.entries()]);
    
    const objToMap = (obj) => new Map(Object.entries(obj));
    
    const serializableDetails = (details) => {
        const { name, address, country, items } = details;
        return { name, address, country, items: mapToObj(items) }
    }
    
    const jsDetails = {
        name: 'Joe Biden',
        address: '1600 Pennsylvania Ave NW, Washington, DC 20500',
        country: 'USA',
        items: objToMap({ foo: 1, bar: 2 }) 
    }
    
    console.log(jsDetails); // Note: the Map will not show in the snippet console
    
    const postDetails = serializableDetails(jsDetails);
    
    console.log(postDetails);
    .as-console-wrapper { top: 0; max-height: 100% !important; }

    Usage

    async function handleSubmit(e: any) {
        e.preventDefault()
        await invoke('submit_new_customer', {
            details: serializableDetails(details); // pre-process here
        })
            .then((submitted) => { ... })
    }