0

Im trying to make the following work

use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let json = reqwest::get("https://www.bitmex.com/api/v1/instrument/indices")
        .await?
        .json::<serde_json::Value>()
        .await?;

    for key in json {
        println!("{:?}", key["symbol"]);
    }

    Ok(())
}

which results in the following

--> src/main.rs:8:16
  |
8 |     for key in json {
  |                ^^^^ `Value` is not an iterator
  |
  = help: the trait `Iterator` is not implemented for `Value`
  = note: required because of the requirements on the impl of `IntoIterator` for `Value`

I tried to implement it in the local source file serde_json-1.0.79/src/value/mod.rs as


impl IntoIterator for Value {
    type Item = Value;
    type IntoIter = ValueIterator;
    fn into_iter(self) -> Self::IntoIter {
        ValueIterator {
            slice: self.as_array().unwrap().iter(),
        }
    }
}

struct ValueIterator {
    slice: std::slice::Iter<Value>,
}

impl Iterator for ValueIterator {
    type Item = Value;

    fn next(&mut self) -> Option<Self::Item> {
        self.slice.next()
    }
}

But the error remains, what can i change in the iterator implementation to make the code work as is?

blanNL
  • 360
  • 1
  • 11
  • 1
    May I suggest that this is an XY problem? If you know the shape of the data you're going to receive, why not make a struct (e.g. `Index`), derive `serde::Deserialize` for it and deserialize the response to something like `Vec`? – justinas Mar 24 '22 at 12:18

1 Answers1

2

You can't. You need to wrap it a new type defined within your crate first before you implement a trait for it. The easy way around this is to make a new trait you can implement on the foreign types which does what you want. Alternatively you can wrap it in a struct to avoid the limitations entirely.

pub trait ValueExt {
    type ArrayIter: IntoIter<Item=Foo>;
    fn json_array_iter(&self) -> Self::ArrayIter;
}

impl ValueExt for Value {
    type ArrayIter = ValueIterator;

    fn json_array_iter(&self) -> Self::ArrayIter {
        ValueIterator {
            slice: self.as_array().unwrap().iter(),
        }
    }
}

// Now you can call your trait while iterating
for item in value.json_array_iter() {
    // etc.
}

That being said, the solution for serde_json is to just expand the Value first to check if it is an array before iterating over the elements.

if let Value::Array(elements) = value_to_iterate {
    for item in elements {
        // etc.
    }
}

Edit:

For fun, here is an iterator that will go through key value pairs of a JSON value. It will work on strings (index, UTF-8 character), arrays (index, value), and maps (key, value).

for (key, value) in json_object.items().unwrap() {
    println!("Key: {:?}, Value: {:?}", key, value);
}

Here is the actual implementation and playground link.

use std::iter::Enumerate;
use std::str::Chars;
use std::slice::Iter;
use serde_json::{json, Value};
use serde_json::map::Iter as MapIter;

pub enum KVIter<'a> {
    StrIter ( Enumerate<Chars<'a>>),
    ArrIter (Enumerate<Iter<'a, Value>>),
    MapIter (MapIter<'a>),
}

impl<'a> Iterator for KVIter<'a> {
    type Item = (Value, Value);
    
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Self::StrIter(chars) => {
                let (idx, character) = chars.next()?;
                Some((json!(idx), json!(character)))
            }
            Self::ArrIter(values) => {
                let (idx, value) = values.next()?;
                Some((json!(idx), value.clone()))
            }
            Self::MapIter(items) => {
                let (key, value) = items.next()?;
                Some((json!(key), value.clone()))
            }
        }
    }
}

pub trait IntoKVIter {
    fn items(&self) -> Option<KVIter>;
}

impl<'a> IntoKVIter for Value {
    fn items(&self) -> Option<KVIter> {
        Some(match self {
            Value::String(string) => KVIter::StrIter(string.chars().enumerate()),
            Value::Array(values) => KVIter::ArrIter(values.into_iter().enumerate()),
            Value::Object(map) => KVIter::MapIter(map.into_iter()),
            _ => return None,
        })
    }
}
Locke
  • 7,626
  • 2
  • 21
  • 41