pub struct Reader<T>{ /* private fields */ }
Implementations§
Source§impl<T> Reader<T>
impl<T> Reader<T>
Sourcepub fn new(iter: T) -> Reader<T>
pub fn new(iter: T) -> Reader<T>
Construct new reader object, that can read values from a JSON stream, passing an object that implements Iterator<Item=u8>
.
This allows to use &str
as data source like this:
let source = "\"Data\"";
let mut reader = Reader::new(source.bytes());
To use &[u8]
do this:
let source: &[u8] = b"\"Data\"";
let mut reader = Reader::new(source.iter().map(|i| *i));
To use std::io::Read
as source, you can convert it to Iterator<Item=u8>
like this:
use std::io::Read;
use nop_json::Reader;
let source = std::io::stdin();
let source = source.lock(); // this implements std::io::Read
let mut reader = Reader::new(source.bytes().map(|b| b.unwrap()));
Though, this will panic on i/o error. Another technique is to use read_iter
crate.
use read_iter::ReadIter;
use nop_json::Reader;
let mut source = ReadIter::new(std::io::stdin());
let mut reader = Reader::new(&mut source);
// ...
source.take_last_error().unwrap();
To read from file:
use std::fs::File;
use read_iter::ReadIter;
use nop_json::Reader;
let mut source = ReadIter::new(File::open("/tmp/test.json").unwrap());
let mut reader = Reader::new(&mut source);
// ...
source.take_last_error().unwrap();
Sourcepub fn unwrap(self) -> T
pub fn unwrap(self) -> T
Destroy this reader, unwrapping the underlying iterator that was passed to constructor when this object created.
Sourcepub fn read<U>(&mut self) -> Result<U>where
U: TryFromJson,
pub fn read<U>(&mut self) -> Result<U>where
U: TryFromJson,
Read one JSON value from the stream.
The value will be converted to target variable type with TryFromJson trait. The conversion is inspired by Javascript values conversion. For example, a JSON string that represents a number (like “123.4e5”) can be read to a numeric variable.
Sourcepub fn read_prop<U>(&mut self, prop: &'static str) -> Result<U>where
U: TryFromJson,
pub fn read_prop<U>(&mut self, prop: &'static str) -> Result<U>where
U: TryFromJson,
This method is intended for use in cases when you want to implement TryFromJson manually.
Use it when you read an object with read_object() or read_object_use_buffer().
It works exactly like read()
, but uses provided static string in error message. This string must be the name of the object property that you are reading.
Sourcepub fn read_index<U>(&mut self) -> Result<U>where
U: TryFromJson,
pub fn read_index<U>(&mut self) -> Result<U>where
U: TryFromJson,
This method is intended for use in cases when you want to implement TryFromJson manually.
Use it when you read an array with read_array().
It works exactly like read()
, but if error occures, the error message will contain index number in array.
The index number is stored internally, and is incremented each time you call read_index()
(read_array()
resets it).
Sourcepub fn format_error(&self, msg: &str) -> Error
pub fn format_error(&self, msg: &str) -> Error
Creates std::io::Error
from given string.
The error message will be prefixed with current path in objects/arrays tree.
This path is built by read_prop() and read_index().
Sourcepub fn format_error_fmt(&self, args: Arguments<'_>) -> Error
pub fn format_error_fmt(&self, args: Arguments<'_>) -> Error
Like format_error(), but receives std::fmt::Arguments
object.
Create it with format_args!()
.
Sourcepub fn read_bytes(&mut self) -> Result<&[u8]>
pub fn read_bytes(&mut self) -> Result<&[u8]>
Reads a JSON string (numbers, booleans and null will be converted to strings) to internal buffer, which is 128 bytes long. And return a reference to the read bytes. Long strings will be truncated.
Sourcepub fn read_blob(&mut self) -> Result<Vec<u8>>
pub fn read_blob(&mut self) -> Result<Vec<u8>>
This function allows us to exploit standard JSON containers to pass binary data (BLOBs, binary large objects, or Vec<u8>
).
Accodring to JSON standard only valid unicode strings are valid JSON values. But the standard doesn’t specify what kind of unicode it must be: utf-8, utf-16, or other. What is invalid utf-8 can be valid utf-16, and what is invalid utf-16 can be valid something else. If we pack an invalid utf-8 sequence to a JSON container and hand it to some other application, that application will encounter errors when it will try to convert it to a string, and it will say that the JSON was invalid. But that application can not convert the bytes to string, and use the bytes themselves.
The wisdom is how to pack bytes that way. There’s trouble here only with bytes in range 80 - FF
. Here is how we can encode our binary object:
00 - 1F
- we can encode with the\u00xx
encoding - this is the only option.20 - 7F
except"
and\
- we can leave intact - they are valid utf-8 JSON, or optionally we can encode them with\u00xx
."
and\
- escape with a slash.80 - FF
- leave them as they are. They make our string invalid utf-8, but we cannot encode them with\u00xx
. Because\u0080
will expand to 2-byte utf-8 character on JSON-decoding.
Decoding example:
use nop_json::Reader;
let mut reader = Reader::new(b" \"\x80\x81\" ".iter().map(|i| *i));
let data = reader.read_blob().unwrap();
assert_eq!(data, b"\x80\x81");
Encoding (and decoding back) example:
use nop_json::{escape_bytes, Reader};
use std::io::Write;
let data = b"\x80\x81";
let mut json_container = Vec::with_capacity(100);
json_container.push(b'"');
json_container.write_all(escape_bytes(data).as_ref()).unwrap();
json_container.push(b'"');
assert_eq!(json_container, vec![b'"', b'\x80', b'\x81', b'"']);
let mut reader = Reader::new(json_container.iter().map(|i| *i));
let data_back = reader.read_blob().unwrap();
assert_eq!(data_back, data);
Sourcepub fn pipe_blob<U>(&mut self, writer: &mut U) -> Result<()>where
U: Write,
pub fn pipe_blob<U>(&mut self, writer: &mut U) -> Result<()>where
U: Write,
Like read_blob(), but pipes data to the provided writer.
Sourcepub fn read_object<F>(&mut self, on_value: F) -> Result<bool>
pub fn read_object<F>(&mut self, on_value: F) -> Result<bool>
This method is intended for use in cases when you want to implement TryFromJson manually. This method reads a JSON object from stream.
First it reads starting {
char from the stream.
Then it reads a property name.
Then for each property name read, it calls given callback function, assuming that from this function you will read the property value using read_prop().
Reading the value with read() will also work, but in case of error, the error message will not contain path to the property where error occured.
Example:
let mut reader = Reader::new(r#" {"x": 10, "y": "the y"} "#.bytes());
let mut x: Option<i32> = None;
let mut y = String::new();
reader.read_object
( |reader, prop|
{ match prop.as_ref()
{ "x" => x = reader.read_prop("x")?,
"y" => y = reader.read_prop("y")?,
_ => return Err(reader.format_error_fmt(format_args!("Invalid property: {}", prop)))
}
Ok(())
}
)?;
assert_eq!(x, Some(10));
assert_eq!(y, "the y".to_string());
Sourcepub fn read_object_use_buffer<F>(&mut self, on_value: F) -> Result<bool>
pub fn read_object_use_buffer<F>(&mut self, on_value: F) -> Result<bool>
This method is intended for use in cases when you want to implement TryFromJson manually. This method reads a JSON object from stream.
First it reads starting {
char from the stream.
Then it reads a property name, and stores it in internal buffer. You can get it with get_key().
The buffer is 128 bytes long, so if the property name is longer, it will be truncated. To avoid this limitation, use read_object().
Then for each property name read, it calls given callback function, assuming that from this function you will read the property value using read_prop().
Reading the value with read() will also work, but in case of error, the error message will not contain path to the property where error occured.
Example:
let mut reader = Reader::new(r#" {"x": 10, "y": "the y"} "#.bytes());
let mut x: Option<i32> = None;
let mut y = String::new();
reader.read_object_use_buffer
( |reader|
{ match reader.get_key()
{ b"x" => x = reader.read_prop("x")?,
b"y" => y = reader.read_prop("y")?,
_ => return Err(reader.format_error_fmt(format_args!("Invalid property: {}", String::from_utf8_lossy(reader.get_key()))))
}
Ok(())
}
)?;
assert_eq!(x, Some(10));
assert_eq!(y, "the y".to_string());
Sourcepub fn read_array<F>(&mut self, on_value: F) -> Result<bool>
pub fn read_array<F>(&mut self, on_value: F) -> Result<bool>
This method is intended for use in cases when you want to implement TryFromJson manually. This method reads a JSON array from stream.
First it reads starting [
char from the stream.
Then it calls given callback function as many times as needed to read each value till terminating ]
.
The callback function is assumed to call read_index() to read next array element.
Example:
let mut reader = Reader::new(r#" ["One", "Two", "Three"] "#.bytes());
let mut value: Vec<String> = Vec::new();
reader.read_array
( |reader|
{ value.push(reader.read_index()?);
Ok(())
}
)?;
assert_eq!(value, vec!["One".to_string(), "Two".to_string(), "Three".to_string()]);