Como posso implementar o valuable::Valuable no meu tipo de wrapper serde_json::Value.
Todos os outros campos estão funcionando, exceto o array e o objeto.
Tentei envolvê-lo com meu tipo personalizado, mas estava dando erro de compilação dizendo que o valor foi descartado.
Também tentei adicionar tempos de vida aos meus tipos personalizados, mas isso também não funcionou.
Aqui está o que fiz até agora, esperando que haja uma solução ou mesmo uma alternativa.
use serde_json::{Map, Value as Json};
use valuable::{Mappable, Valuable, Value, Visit};
#[derive(Clone)]
pub struct JsonValueable(pub Json);
#[derive(Clone)]
pub struct JsonValueableMap(pub Map<String, Json>);
impl Valuable for JsonValueable {
fn as_value(&self) -> Value<'_> {
match self.0 {
Json::Array(ref array) => array
.iter()
.map(|v| JsonValueable(v.clone()))
.collect::<Vec<JsonValueable>>()
.as_value(),
Json::Bool(ref value) => value.as_value(),
Json::Number(ref num) => {
if num.is_f64() {
Value::F64(num.as_f64().unwrap())
} else if num.is_i64() {
Value::I64(num.as_i64().unwrap())
} else {
unreachable!()
}
}
Json::Null => Value::Unit,
Json::String(ref s) => s.as_value(),
Json::Object(ref object) => JsonValueableMap(object.clone()).as_value(),
}
}
fn visit(&self, visit: &mut dyn Visit) {
match self.0 {
Json::Array(ref array) => array
.iter()
.map(|v| JsonValueable(v.clone()))
.for_each(|v| v.visit(visit)),
Json::Bool(ref value) => value.visit(visit),
Json::Number(ref num) => {
if num.is_f64() {
num.as_f64().unwrap().visit(visit)
} else if num.is_i64() {
num.as_i64().unwrap().visit(visit)
} else {
unreachable!()
}
}
Json::Null => Value::Unit.visit(visit),
Json::String(ref s) => s.visit(visit),
Json::Object(ref object) => JsonValueableMap(object.clone()).visit(visit),
}
}
}
impl Valuable for JsonValueableMap {
fn as_value(&self) -> Value<'_> {
Value::Mappable(self)
}
fn visit(&self, visit: &mut dyn Visit) {
for (k, v) in self.0.iter() {
visit.visit_entry(k.as_value(), JsonValueable(v.clone()).as_value());
}
}
}
impl Mappable for JsonValueableMap {
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.0.len();
(len, Some(len))
}
}
Este é o erro que encontro
error[E0515]: cannot return value referencing temporary value
--> bins/api/src/utils/json_valuable.rs:14:39
|
14 | Json::Array(ref array) => array
| _______________________________________^
| |_______________________________________|
15 | || .iter()
16 | || .map(|v| JsonValueable(v.clone()))
17 | || .collect::<Vec<JsonValueable>>()
| ||________________________________________________- temporary value created here
18 | | .as_value(),
| |____________________________^ returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing temporary value
--> bins/api/src/utils/json_valuable.rs:31:41
|
31 | Json::Object(ref object) => JsonValueableMap(object.clone()).as_value(),
| --------------------------------^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| temporary value created here
For more information about this error, try `rustc --explain E0515`.
error: could not compile `api` (bin "api") due to 2 previous errors
Vejo apenas uma opção: um newtype transparente e um pouco de
unsafe
.Resumindo, você precisa retornar a,
valuable::Value
mas todas as variantes aninhadas exigem referências — o que, para retorná-las, significa que elas devem vir do seuself
valor e não de um valor intermediário. O ideal seria retornar apenas as,&serde_json::Map
mas&dyn Mappable
é claro que essa implementação não é definida e não pode ser definida por você.O código abaixo mostra como obter um
&JsonValueableMap
de um&Map<String, Json>
que usa o mesmo tempo de vida:É assim que
Path::new
funciona. Com isso, oValuable
forJsonValueable
fica mais simples:JsonValuableArray
Você também precisaria criar o seu próprio e provavelmente fornecer o mesmo paraJsonValuable
pular mais.clone()
s em outros lugares. Aqui está a implementação completa (não compila no playground porque não temvaluable
).Se você não quiser nenhum
unsafe
diretamente no seu código, há o ref-cast crate que faz isso para você.