The trait `AsRef<str>` is not implemented for `u64` when json::stringify BtreeMap

I use this crate for json parsing: https://crates.io/crates/json

I have a Player struct with implemented traits for JsonValue and if Player instance is single code works OK:

pub struct Player {
    id: u64,
    name: String,
}

impl Into<JsonValue> for Player {
    fn into(self) -> JsonValue {
        json::object! {
            "id" => self.id,
            "name" => self.name,
        }
    }
}

impl From<&Player> for JsonValue {
    fn from(player: &Player) -> JsonValue {
        JsonValue::Object(player.into())
    }
}

impl From<&Player> for json::object::Object {
    fn from(player: &Player) -> json::object::Object {
        player.into()
    }
}

when I try to use Player instances inside BTreeMap I got an error:

67   | ...                   JsonValue::Object(players.into_iter().collect())
     |                       ----------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsRef<str>` is not implemented for `u64`
     |                       |
     |                       required by a bound introduced by this call

This is how I use it:

use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use tokio::task::JoinHandle;
use futures::future::join_all;
use json::JsonValue;
use ws::{listen, Message};

pub struct WSServer {
    db: Arc<Mutex<DB>>,
    players_map: Arc<Mutex<BTreeMap<u64, Player>>>,
}

impl WSServer {
    pub async fn new() -> Self {
        let db = DB::new().await;

        Self {
            db: Arc::new(Mutex::new(db)),
            players_map: Arc::new(Mutex::new(BTreeMap::new())),
        }
    }

    pub async fn run(&mut self) {
        join_all(vec![
            self.listen(),
            // ...
        ]).await;
    }

    fn listen(&mut self) -> JoinHandle<()> {
        let players_map = Arc::clone(&self.players_map);

        tokio::task::spawn_blocking(move || {
            listen("...", |out| {
                let players_map = Arc::clone(&players_map);
                move |msg: Message| {
                    let request = json::parse(msg.as_text().unwrap());
                    let message = match request {
                        Ok(result) => {
                            let event = result["event"].dump();

                            match event.as_str() {...},
                                "players.all" => {
                                    let players = &*players_map.lock().unwrap();

                                    Message::from(
                                        json::stringify(
                                            JsonValue::Object(players.into_iter().collect())
                                        )
                                    )
                                },
                                "players.sync" => {...},
                                _ => {...},
                            }
                        },
                        Err(err) => {...},
                    };

                    out.send(message)
                }
            }).unwrap();
        })
    }
}

Unfortunately, play-rust not support json crate, I cannot create minimal reproduced sandbox example.

Could somebody help to solve the issue ?

The issue is that u64 doesn't implement AsRef<str>, but that is required by the FromIterator implementation for json::object::Object (which collect() uses). The json crate expects you to have string keys when creating an Object, so the simplest way to fix this would be to do something like:

JsonValue::Object(players.into_iter().map(|(key, value)| (key.to_string(), value)).collect())

in order to convert the u64 keys to String.

2 Likes