I have the following code:
extern crate serialize;
use std::collections::TreeMap;
use serialize::json;
use serialize::json::ToJson;
use serialize::json::Json;
fn main() {
let mut tree_map = get_tree_map(); // : TreeMap<String, String>
let mut tree_map2 = tree_map.iter().map(|k, v| (k, v.to_json())); //error the type of this value must be known in this context
let json1 = json::Object(tree_map2);
}
I want to convert tree_map to json. I tried to do it by converting it to TreeMap<String, Json> but failed. How can I do that?
The closure you passed to map takes two parameters, but it should take a single parameter that is a tuple type, because iter() returns an iterator over tuples (see Trait Implementations on Entries). Change |k, v| to |(k, v)| to fix this. (I found this by adding explicit type annotations on k, v: the compiler then complained about the closure not having the right number of parameters.)
There are some other errors however. Instead of using iter(), you might want to use into_iter() to avoid cloning the Strings if you don't need the TreeMap<String, String> anymore. Also, you should add .collect() after .map(...) to turn the iterator into a TreeMap. The compiler will automatically infer the type for tree_map2 based on the requirements for json::Object.
fn main() {
let mut tree_map = get_tree_map(); // : TreeMap<String, String>
let mut tree_map2 = tree_map.into_iter().map(|(k, v)| (k, v.to_json())).collect();
let json1 = Json::Object(tree_map2);
}
Related
I am trying to use the Rust tracing_distributed package, but I am getting strange and unhelpful errors when using it, and I am assuming I am using it wrong, but there is no documentation and there are no examples about how to use it. Here is an example of what I'm trying to do :
let trace = tracing_distributed::register_dist_tracing_root(traceId, remote_parent_span_id));
println!("trace value: {:?}", trace);
// the result of trace is: Err(NoEnabledSpan)
I have tried passing a few things in as the traceID and remote_parent_span_id including:
traceId = remote_parent_span_id = Some(tracing::Span::current())
As well as:
traceId = Some(tracing::Span::current())
remote_parent_span_id = ~someParentRequestIdGeneratedUpstream~
I know that the current span is not disabled from trying:
let span = tracing::Span::current();
if span.is_disabled() {
println!("CURRENT SPAN DISABELED");
}
So this leads me to think that the issue is coming from not having the subscriber set properly. I am trying to set the subscriber in an init function which is called before this function which looks like this:
let subscriber = tracing_subscriber::registry() // provide underlying span data store
.with(
tracing_subscriber::fmt::layer()
.json()
.with_span_events(FmtSpan::ACTIVE)
.event_format(stackdriver::StackDriverEventFormat::default())
.with_filter(tracing_subscriber::filter::dynamic_filter_fn(
move |m, c| filter_layer.enabled(m, c.to_owned()),
)),
);
let _ = tracing::subscriber::set_global_default(subscriber)
.map_err(|_err| eprintln!("Unable to set global default subscriber"));
Would anyone be willing to provide me with an example of how to use this library? Or can anyone see what I'm doing wrong here? I have tried everything I can think of.
tracing-distributed has a test which demonstrates how to create and use TelemetryLayer.
I made a demo based on it. In this demo, NoEnabledSpan may be caused by missing #[instrument], which creates a Span for function foo. Hope this will help you find the actual cause.
Also tracing-honeycomb is a great use case for tracing-distributed, better check it out.
use std::sync::{Arc, Mutex};
use tracing::{Id, info};
use tracing::instrument;
use tracing_distributed::{Event, Span, Telemetry, TelemetryLayer};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::registry;
#[derive(Default, Debug)]
pub struct BlackholeVisitor;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct TraceId(pub(crate) u128);
type SpanId = tracing::Id;
impl tracing::field::Visit for BlackholeVisitor {
fn record_debug(&mut self, _: &tracing::field::Field, _: &dyn std::fmt::Debug) {}
}
/// Mock telemetry capability
pub struct TestTelemetry {
spans: Arc<Mutex<Vec<Span<BlackholeVisitor, SpanId, TraceId>>>>,
events: Arc<Mutex<Vec<Event<BlackholeVisitor, SpanId, TraceId>>>>,
}
impl TestTelemetry {
pub fn new(
spans: Arc<Mutex<Vec<Span<BlackholeVisitor, SpanId, TraceId>>>>,
events: Arc<Mutex<Vec<Event<BlackholeVisitor, SpanId, TraceId>>>>,
) -> Self {
TestTelemetry { spans, events }
}
}
impl Telemetry for TestTelemetry {
type Visitor = BlackholeVisitor;
type TraceId = TraceId;
type SpanId = SpanId;
fn mk_visitor(&self) -> Self::Visitor {
BlackholeVisitor
}
fn report_span(&self, span: Span<BlackholeVisitor, SpanId, TraceId>) {
// succeed or die. failure is unrecoverable (mutex poisoned)
let mut spans = self.spans.lock().unwrap();
spans.push(span);
}
fn report_event(&self, event: Event<BlackholeVisitor, SpanId, TraceId>) {
// succeed or die. failure is unrecoverable (mutex poisoned)
let mut events = self.events.lock().unwrap();
events.push(event);
}
}
#[instrument]
fn foo() {
let trace = tracing_distributed::register_dist_tracing_root(TraceId(123), Option::<Id>::None);
println!("trace value: {:?}", trace);
info!("test");
}
fn main() {
let spans = Arc::new(Mutex::new(Vec::new()));
let events = Arc::new(Mutex::new(Vec::new()));
let cap = TestTelemetry::new(spans.clone(), events.clone());
let telemetry_layer = TelemetryLayer::new("test_svc_name", cap, |x| x);
let subscriber = registry::Registry::default()
.with(tracing_subscriber::fmt::Layer::default())
.with(telemetry_layer);
// dbg!(&subscriber);
tracing::subscriber::set_global_default(subscriber).expect("setting global default failed");
foo();
dbg!(&spans);
dbg!(&events);
}
crate versions:
tracing = "0.1.32"
tracing-distributed = "0.4.0"
tracing-subscriber = "0.3.10"
I'm using the CSV crate to read CSV files. I then parse the content. I would like to unit test the parsing logic. Here's a simplified version of the code:
fn main() -> Result<(), Box<dyn Error>> {
let mut rdr = csv::ReaderBuilder::new()
.from_path("test.csv")?;
process(rdr.records());
Ok(())
}
fn process(iter: StringRecordsIter<File>) -> Result<String, String> {
for result in iter {
// Parsing takes place here
println!("{:?}", result);
}
// Post-parsing using entire file content takes place here
Ok(String::from("My Result Here"))
}
In my unit test I would like to be able to construct sequences of StringRecord objects, pass them to the process() method and validate the results. I can successfully create a StringRecord using the simple StringRecord::new() and fill it with values using record.push_field("my field value"). However, I'm struggling to create an iterator that returns my values to pass to the process(). Any suggestions? I'm happy to change the arguments to process() if this makes things easier.
The suggestion made by Jmb to change the signature of process() to fn process(iter: impl Iterator<Item = csv::Result<StringRecord>>) -> Result<String, String> works nicely.
Here's the solution in detail. Firstly the only change to process() is to make it accept more types:
fn process(iter: impl Iterator<Item = csv::Result<StringRecord>>) -> Result<String, String> {
for result in iter {
// Parsing takes place here
println!("{:?}", result);
}
// Post-parsing using entire file content takes place here
Ok(String::from("My Result Here"))
}
The main() remains identical as rdr.records can still be passed to process(). Then the testing looks like this:
#[test]
fn my_test() -> Result<(), String> {
let record1 = result_record(&["Value 1", "Value 2"]);
let record2 = result_record(&["Value 3", "Value 4"]);
let records = vec![record1, record2];
let result = process(records.into_iter())?;
assert_eq!("My Result Here", result);
Ok(())
}
fn result_record(fields: &[&str]) -> csv::Result<StringRecord> {
let mut record = StringRecord::new();
for field in fields {
record.push_field(field);
}
Ok(record)
}
I'm trying to create a generic method like the following:
private func map<T>(type:T, jsonString:String) -> T
{
do
{
let model = try Mapper<type>().map(JSONString: jsonString)!
return model
}
catch
{
Log.error("Failed to convert JSON jsonString to model object: \(jsonString)")
}
return EmptyModel()
}
but it result in compile error:
Error: use of undeclared type 'type'
How can I change it to use the specified type (a class object) with the Mapper's generic value?
You can use T instead of type:
let model = try Mapper<T>().map(JSONString: jsonString)!
You might want to change method signature, so it returns an instance of T and not the type T itself:
private func map<T>(type: T.Type, jsonString: String) -> T
That being said, Swift already has its JSONDecoder. It might already support what you are trying to implement.
let decoder = JSONDecoder()
let model = try decoder.decode(Model.self, from: data)
I am writing a websocket server which deserializes incoming frames into a serde_json::Value and then passes this value to (potentially many) callbacks. I would like the callbacks to convert the serde_json::Value to a new type (e.g. MyType in the example below) without an encode/decode pass. It seems to me that the serde machinery should have enough information to do this (with the possibility of an error if the contained fields and types do not match). In the example below, the function to_my_type() stands in for this callback function. Is is the encode/decode that I want to bypass from this function.
I could of course pass the raw encoded data to each callback, but then each callback will have to do the decoding separately. I want to keep the function signature of the callbacks taking an argument of type serde_json::Value so that different callbacks can get different types but that I can register them all with a common function signature.
#![feature(proc_macro)]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[derive(Serialize, Deserialize)]
struct MyType {
a: bool,
}
fn as_json(a: &MyType) -> serde_json::Value {
let buf = serde_json::to_vec(a).unwrap();
serde_json::from_slice::<serde_json::Value>(&buf).unwrap()
}
fn to_my_type(value: serde_json::Value) -> MyType {
// How to convert a serde_json::Value into MyType without encode/decode pass?
let buf = serde_json::to_vec(&value).unwrap();
serde_json::from_slice::<MyType>(&buf).unwrap()
}
fn main() {
let store = MyType{a: true};
let raw_json = as_json(&store);
let _store2 = to_my_type(raw_json);
}
You can use the serde_json::from_value function to convert a Value to any type that implements Deserialize:
fn to_my_type(value: serde_json::Value) -> MyType {
serde_json::from_value(value).unwrap()
}
I want to convert json to TreeMap in a simple way, here's my attempt:
extern crate serialize;
use serialize::json;
use serialize::json::ToJson;
use serialize::json::Json;
use std::collections::TreeMap;
fn main() {
let mut tree_map1 = TreeMap::new();
tree_map1.insert("key1".to_string(), "val1".to_json());
tree_map1.insert("key2".to_string(), "val2".to_json());
//... and so on, the number of keys aren't known
let json1 = json::Object(tree_map1);
let mut tree_map2 = TreeMap::new();
for (k, v) in json1.iter() { //impossible to iterate
tree_map2.insert(k.to_string(), v.to_string());
}
}
UPDATE:
How do I convert TreeMap<String, json::Json> to TreeMap<String, String> ?
let json1 = get_json1(); // json made of TreeMap<String, json::Json>
let res = match json1 {
json::Object(json2) => json2.map(|k, v| ??? ),
_ => panic!("Error")
}
Here is a demonstration of safely converting Json into TreeMap<String, String>:
use serialize::json::Json;
use std::collections::TreeMap;
fn extract_string_map(json: Json) -> Result<TreeMap<String, String>, Json> {
let json = match json {
Json::Object(json) => json,
_ => return Err(json),
};
if !json.iter().all(|(_k, v)| v.is_string()) {
return Err(Json::Object(json));
}
Ok(json.into_iter().map(|(k, v)| (k, match v {
Json::String(s) => s,
_ => unreachable!(),
}))
.collect())
}
This demonstrates a principle of avoiding panic-prone behaviour, for this cannot fail. Also it doesn’t lose any data—should the data not fit the format, the original data is returned intact for the caller to decide what to do with it, without having needed to clone data at any point.
(As a point of curiosity, I think that this restructuring of a TreeMap is going to be fairly inefficient, requiring more rebalancing of the tree than it should, because of the keys being given in order. For performance it’d be great to have a value-changing method for a TreeMap, consuming self and producing a new type more efficiently.)
json::Object is an enum variant which contains TreeMap inside it. So in order to get a TreeMap from it, you just need to unwrap it:
let json1 = json::Object(tree_map1);
let tree_map2 = match json1 {
json::Object(tm) => tm,
_ => unreachable!()
};
This will consume json1. If you don't want it, you need to clone the map:
let tree_map2 = match json1 {
json::Object(ref tm) => tm.clone(),
_ => unreachable!()
};
The latter can be rewritten less noisily with as_object() method:
let tree_map2 = json1.as_object().unwrap().clone();
If you need to obtain TreeMap<String, String> from TreeMap<String, Json> which is contained inside Object variant, you need to convert Json to String somehow. If you know in advance that all values are JSON strings, you can use pattern matching again:
let tree_map2 = match json1 {
json::Object(tm) => tm.into_iter().map(|(k, v)| (k, match v {
json::String(s) => s,
_ => unreachable!()
})).collect(),
_ => unreachable!()
};