#![allow(clippy::missing_safety_doc)]
+use std::cmp::max;
+use std::collections::TryReserveError;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::str::Utf8Error;
pub enum JsonError {
InvalidState,
Utf8Error(Utf8Error),
+ Memory,
}
impl std::error::Error for JsonError {}
match self {
JsonError::InvalidState => write!(f, "invalid state"),
JsonError::Utf8Error(ref e) => e.fmt(f),
+ JsonError::Memory => write!(f, "memory error"),
}
}
}
+impl From<TryReserveError> for JsonError {
+ fn from(_: TryReserveError) -> Self {
+ JsonError::Memory
+ }
+}
+
impl From<Utf8Error> for JsonError {
fn from(e: Utf8Error) -> Self {
JsonError::Utf8Error(e)
impl JsonBuilder {
/// Returns a new JsonBuilder in object state.
- pub fn new_object() -> Self {
- Self::new_object_with_capacity(INIT_SIZE)
+ pub fn try_new_object() -> Result<Self, JsonError> {
+ Self::try_new_object_with_capacity(INIT_SIZE)
}
- pub fn new_object_with_capacity(capacity: usize) -> Self {
- let mut buf = String::with_capacity(capacity);
+ pub fn try_new_object_with_capacity(capacity: usize) -> Result<Self, JsonError> {
+ let mut buf = String::new();
+ buf.try_reserve(capacity)?;
buf.push('{');
- Self {
+ let mut state = Vec::new();
+ state.try_reserve(32)?;
+ state.extend_from_slice(&[State::None, State::ObjectFirst]);
+ Ok(Self {
buf,
- state: vec![State::None, State::ObjectFirst],
+ state,
init_type: Type::Object,
- }
+ })
}
/// Returns a new JsonBuilder in array state.
- pub fn new_array() -> Self {
- Self::new_array_with_capacity(INIT_SIZE)
+ pub fn try_new_array() -> Result<Self, JsonError> {
+ Self::try_new_array_with_capacity(INIT_SIZE)
}
- pub fn new_array_with_capacity(capacity: usize) -> Self {
- let mut buf = String::with_capacity(capacity);
+ pub fn try_new_array_with_capacity(capacity: usize) -> Result<Self, JsonError> {
+ let mut buf = String::new();
+ buf.try_reserve(capacity)?;
buf.push('[');
- Self {
+ let mut state = Vec::new();
+ state.try_reserve(32)?;
+ state.extend_from_slice(&[State::None, State::ArrayFirst]);
+ Ok(Self {
buf,
- state: vec![State::None, State::ArrayFirst],
+ state,
init_type: Type::Array,
+ })
+ }
+
+ /// A wrapper around String::push that pre-allocates data return
+ /// an error if unable to.
+ pub fn push(&mut self, ch: char) -> Result<&mut Self, JsonError> {
+ if self.buf.capacity() == self.buf.len() {
+ self.buf.try_reserve(INIT_SIZE)?;
}
+ self.buf.push(ch);
+ Ok(self)
+ }
+
+ /// A wrapper around String::push_str that pre-allocates data
+ /// return an error if unable to.
+ pub fn push_str(&mut self, s: &str) -> Result<&mut Self, JsonError> {
+ if self.buf.capacity() < self.buf.len() + s.len() {
+ self.buf.try_reserve(max(INIT_SIZE, s.len()))?;
+ }
+ self.buf.push_str(s);
+ Ok(self)
}
// Reset the builder to its initial state, without losing
// the current capacity.
pub fn reset(&mut self) {
self.buf.truncate(0);
+ self.state.clear();
match self.init_type {
Type::Array => {
self.buf.push('[');
- self.state = vec![State::None, State::ArrayFirst];
+ self.state
+ .extend_from_slice(&[State::None, State::ArrayFirst]);
}
Type::Object => {
self.buf.push('{');
- self.state = vec![State::None, State::ObjectFirst];
+ self.state
+ .extend_from_slice(&[State::None, State::ObjectFirst]);
}
}
}
pub fn close(&mut self) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectFirst | State::ObjectNth => {
- self.buf.push('}');
+ self.push('}')?;
self.pop_state();
Ok(self)
}
State::ArrayFirst | State::ArrayNth => {
- self.buf.push(']');
+ self.push(']')?;
self.pop_state();
Ok(self)
}
}
/// Move to a new state.
- fn push_state(&mut self, state: State) {
+ fn push_state(&mut self, state: State) -> Result<(), JsonError> {
+ if self.state.len() == self.state.capacity() {
+ self.state.try_reserve(32)?;
+ }
self.state.push(state);
+ Ok(())
}
/// Go back to the previous state.
pub fn open_object(&mut self, key: &str) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectFirst => {
- self.buf.push('"');
+ self.push('"')?;
self.set_state(State::ObjectNth);
}
State::ObjectNth => {
- self.buf.push_str(",\"");
+ self.push_str(",\"")?;
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
- self.buf.push_str(key);
- self.buf.push_str("\":{");
- self.push_state(State::ObjectFirst);
+ self.push_str(key)?;
+ self.push_str("\":{")?;
+ self.push_state(State::ObjectFirst)?;
Ok(self)
}
match self.current_state() {
State::ArrayFirst => {}
State::ArrayNth => {
- self.buf.push(',');
+ self.push(',')?;
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
- self.buf.push('{');
+ self.push('{')?;
self.set_state(State::ArrayNth);
- self.push_state(State::ObjectFirst);
+ self.push_state(State::ObjectFirst)?;
Ok(self)
}
match self.current_state() {
State::ObjectFirst => {}
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":[");
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":[")?;
self.set_state(State::ObjectNth);
- self.push_state(State::ArrayFirst);
+ self.push_state(State::ArrayFirst)?;
Ok(self)
}
Ok(self)
}
State::ArrayNth => {
- self.buf.push(',');
+ self.push(',')?;
self.encode_string(val)?;
Ok(self)
}
pub fn append_string_from_bytes(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
match std::str::from_utf8(val) {
Ok(s) => self.append_string(s),
- Err(_) => self.append_string(&string_from_bytes(val)),
+ Err(_) => self.append_string(&try_string_from_bytes(val)?),
}
}
pub fn append_base64(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ArrayFirst => {
- self.buf.push('"');
- base64::encode_config_buf(val, base64::STANDARD, &mut self.buf);
- self.buf.push('"');
+ self.push('"')?;
+ self.encode_base64(val)?;
+ self.push('"')?;
self.set_state(State::ArrayNth);
Ok(self)
}
State::ArrayNth => {
- self.buf.push(',');
- self.buf.push('"');
- base64::encode_config_buf(val, base64::STANDARD, &mut self.buf);
- self.buf.push('"');
+ self.push(',')?;
+ self.push('"')?;
+ self.encode_base64(val)?;
+ self.push('"')?;
Ok(self)
}
_ => {
pub fn append_hex(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ArrayFirst => {
- self.buf.push('"');
+ self.push('"')?;
for i in 0..val.len() {
- self.buf.push(HEX[(val[i] >> 4) as usize] as char);
- self.buf.push(HEX[(val[i] & 0xf) as usize] as char);
+ self.push(HEX[(val[i] >> 4) as usize] as char)?;
+ self.push(HEX[(val[i] & 0xf) as usize] as char)?;
}
- self.buf.push('"');
+ self.push('"')?;
self.set_state(State::ArrayNth);
Ok(self)
}
State::ArrayNth => {
- self.buf.push(',');
- self.buf.push('"');
+ self.push(',')?;
+ self.push('"')?;
for i in 0..val.len() {
- self.buf.push(HEX[(val[i] >> 4) as usize] as char);
- self.buf.push(HEX[(val[i] & 0xf) as usize] as char);
+ self.push(HEX[(val[i] >> 4) as usize] as char)?;
+ self.push(HEX[(val[i] & 0xf) as usize] as char)?;
}
- self.buf.push('"');
+ self.push('"')?;
Ok(self)
}
_ => {
self.set_state(State::ArrayNth);
}
State::ArrayNth => {
- self.buf.push(',');
+ self.push(',')?;
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
- self.buf.push_str(&val.to_string());
- Ok(self)
+ self.push_str(&val.to_string())
}
pub fn append_float(&mut self, val: f64) -> Result<&mut Self, JsonError> {
self.set_state(State::ArrayNth);
}
State::ArrayNth => {
- self.buf.push(',');
+ self.push(',')?;
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
- self.buf.push_str(&val.to_string());
+ self.push_str(&val.to_string())?;
Ok(self)
}
pub fn set_object(&mut self, key: &str, js: &JsonBuilder) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":");
- self.buf.push_str(&js.buf);
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":")?;
+ self.push_str(&js.buf)?;
Ok(self)
}
self.set_state(State::ArrayNth);
}
State::ArrayNth => {
- self.buf.push(',');
+ self.push(',')?;
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
- self.buf.push_str(&js.buf);
+ self.push_str(&js.buf)?;
Ok(self)
}
pub fn set_string(&mut self, key: &str, val: &str) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":");
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":")?;
self.encode_string(val)?;
Ok(self)
}
pub fn set_formatted(&mut self, formatted: &str) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push_str(formatted);
+ self.push_str(formatted)?;
Ok(self)
}
pub fn set_string_from_bytes(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
match std::str::from_utf8(val) {
Ok(s) => self.set_string(key, s),
- Err(_) => self.set_string(key, &string_from_bytes(val)),
+ Err(_) => self.set_string(key, &try_string_from_bytes(val)?),
}
}
pub fn set_base64(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":\"");
- base64::encode_config_buf(val, base64::STANDARD, &mut self.buf);
- self.buf.push('"');
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":\"")?;
+ self.encode_base64(val)?;
+ self.push('"')?;
Ok(self)
}
pub fn set_hex(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":\"");
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":\"")?;
for i in 0..val.len() {
- self.buf.push(HEX[(val[i] >> 4) as usize] as char);
- self.buf.push(HEX[(val[i] & 0xf) as usize] as char);
+ self.push(HEX[(val[i] >> 4) as usize] as char)?;
+ self.push(HEX[(val[i] & 0xf) as usize] as char)?;
}
- self.buf.push('"');
+ self.push('"')?;
Ok(self)
}
pub fn set_uint(&mut self, key: &str, val: u64) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":");
- self.buf.push_str(&val.to_string());
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":")?;
+ self.push_str(&val.to_string())?;
Ok(self)
}
pub fn set_float(&mut self, key: &str, val: f64) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
- self.buf.push_str("\":");
- self.buf.push_str(&val.to_string());
+ self.push('"')?;
+ self.push_str(key)?;
+ self.push_str("\":")?;
+ self.push_str(&val.to_string())?;
Ok(self)
}
pub fn set_bool(&mut self, key: &str, val: bool) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
- self.buf.push(',');
+ self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
return Err(JsonError::InvalidState);
}
}
- self.buf.push('"');
- self.buf.push_str(key);
+ self.push('"')?;
+ self.push_str(key)?;
if val {
- self.buf.push_str("\":true");
+ self.push_str("\":true")?;
} else {
- self.buf.push_str("\":false");
+ self.push_str("\":false")?;
}
Ok(self)
}
///
/// The string is encoded into an intermediate vector as its faster
/// than building onto the buffer.
+ ///
+ /// TODO: Revisit this, would be nice to build directly onto the
+ /// existing buffer.
#[inline(always)]
fn encode_string(&mut self, val: &str) -> Result<(), JsonError> {
- let mut buf = vec![0; val.len() * 2 + 2];
+ let mut buf = Vec::new();
+
+ // Start by allocating a reasonable size buffer, it will be
+ // grown if needed.
+ buf.try_reserve(val.len() * 2 + 2)?;
+ buf.resize(val.len() * 2 + 2, 0);
+
let mut offset = 0;
let bytes = val.as_bytes();
buf[offset] = b'"';
offset += 1;
for &x in bytes.iter() {
if offset + 7 >= buf.capacity() {
- let mut extend = vec![0; buf.capacity()];
- buf.append(&mut extend);
+ // We could be smarter, but just double the buffer size.
+ buf.try_reserve(buf.capacity())?;
+ buf.resize(buf.capacity(), 0);
}
let escape = ESCAPED[x as usize];
if escape == 0 {
offset += 1;
match std::str::from_utf8(&buf[0..offset]) {
Ok(s) => {
- self.buf.push_str(s);
+ self.push_str(s)?;
}
Err(err) => {
let error = format!(
&buf[0..offset],
val.as_bytes(),
);
- self.buf.push_str(&error);
+ self.push_str(&error)?;
}
}
Ok(())
}
+
+ fn encode_base64(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
+ let encoded_len = 4 * ((val.len() + 2) / 3);
+ if self.buf.capacity() < self.buf.len() + encoded_len {
+ self.buf.try_reserve(encoded_len)?;
+ }
+ base64::encode_config_buf(val, base64::STANDARD, &mut self.buf);
+ Ok(self)
+ }
}
/// A Suricata specific function to create a string from bytes when UTF-8 decoding fails.
///
/// For bytes over 0x0f, we encode as hex like "\xf2".
-fn string_from_bytes(input: &[u8]) -> String {
- let mut out = String::with_capacity(input.len());
+fn try_string_from_bytes(input: &[u8]) -> Result<String, JsonError> {
+ let mut out = String::new();
+
+ // Allocate enough data to handle the worst case scenario of every
+ // byte needing to be presented as a byte.
+ out.try_reserve(input.len() * 4)?;
+
for b in input.iter() {
if *b < 128 {
out.push(*b as char);
out.push_str(&format!("\\x{:02x}", *b));
}
}
- return out;
+ return Ok(out);
}
#[no_mangle]
pub extern "C" fn jb_new_object() -> *mut JsonBuilder {
- let boxed = Box::new(JsonBuilder::new_object());
- Box::into_raw(boxed)
+ match JsonBuilder::try_new_object() {
+ Ok(js) => {
+ let boxed = Box::new(js);
+ Box::into_raw(boxed)
+ }
+ Err(_) => std::ptr::null_mut(),
+ }
}
#[no_mangle]
pub extern "C" fn jb_new_array() -> *mut JsonBuilder {
- let boxed = Box::new(JsonBuilder::new_array());
- Box::into_raw(boxed)
+ match JsonBuilder::try_new_array() {
+ Ok(js) => {
+ let boxed = Box::new(js);
+ Box::into_raw(boxed)
+ }
+ Err(_) => std::ptr::null_mut(),
+ }
}
#[no_mangle]
mod test {
use super::*;
+ #[test]
+ fn test_try_reserve() {
+ // Just a sanity check that try_reserve works as I expect.
+ let mut buf = String::new();
+ assert_eq!(buf.len(), 0);
+ assert_eq!(buf.capacity(), 0);
+
+ buf.try_reserve(1).unwrap();
+ assert_eq!(buf.len(), 0);
+ assert!(buf.capacity() >= 1);
+ }
+
#[test]
fn test_set_bool() {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_bool("first", true).unwrap();
assert_eq!(jb.buf, r#"{"first":true"#);
jb.set_bool("second", false).unwrap();
assert_eq!(jb.buf, r#"{"first":true,"second":false"#);
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_bool("first", false).unwrap();
assert_eq!(jb.buf, r#"{"first":false"#);
jb.set_bool("second", true).unwrap();
#[test]
fn test_object_in_object() -> Result<(), JsonError> {
- let mut js = JsonBuilder::new_object();
+ let mut js = JsonBuilder::try_new_object().unwrap();
js.open_object("object")?;
assert_eq!(js.current_state(), State::ObjectFirst);
#[test]
fn test_empty_array_in_object() -> Result<(), JsonError> {
- let mut js = JsonBuilder::new_object();
+ let mut js = JsonBuilder::try_new_object().unwrap();
js.open_array("array")?;
assert_eq!(js.current_state(), State::ArrayFirst);
#[test]
#[cfg(not(feature = "debug-validate"))]
fn test_array_in_object() -> Result<(), JsonError> {
- let mut js = JsonBuilder::new_object();
+ let mut js = JsonBuilder::try_new_object().unwrap();
// Attempt to add an item, should fail.
assert_eq!(
#[test]
fn basic_test() -> Result<(), JsonError> {
- let mut js = JsonBuilder::new_object();
+ let mut js = JsonBuilder::try_new_object().unwrap();
assert_eq!(js.current_state(), State::ObjectFirst);
assert_eq!(js.buf, "{");
#[test]
fn test_combine() -> Result<(), JsonError> {
- let mut main = JsonBuilder::new_object();
- let mut obj = JsonBuilder::new_object();
+ let mut main = JsonBuilder::try_new_object().unwrap();
+ let mut obj = JsonBuilder::try_new_object().unwrap();
obj.close()?;
- let mut array = JsonBuilder::new_array();
+ let mut array = JsonBuilder::try_new_array().unwrap();
array.append_string("one")?;
array.append_uint(2)?;
array.close()?;
#[test]
fn test_objects_in_array() -> Result<(), JsonError> {
- let mut js = JsonBuilder::new_array();
+ let mut js = JsonBuilder::try_new_array()?;
assert_eq!(js.buf, r#"["#);
js.start_object()?;
#[test]
fn test_grow() -> Result<(), JsonError> {
- let mut jb = JsonBuilder::new_object_with_capacity(1);
- assert_eq!(jb.capacity(), 1);
- jb.set_string("foo", "bar")?;
- assert!(jb.capacity() > 1);
+ let mut jb = JsonBuilder::try_new_object_with_capacity(1).unwrap();
+
+ // For efficiency reasons, more capacity may be allocated than
+ // requested.
+ assert!(jb.capacity() > 0);
+ let capacity = jb.capacity();
+
+ let mut value = String::new();
+ for i in 0..capacity {
+ value.push_str((i % 10).to_string().as_str());
+ }
+ jb.set_string("foo", &value)?;
+ assert!(jb.capacity() > capacity);
Ok(())
}
#[test]
fn test_reset() -> Result<(), JsonError> {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
assert_eq!(jb.buf, "{");
jb.set_string("foo", "bar")?;
let cap = jb.capacity();
#[test]
fn test_append_string_from_bytes() -> Result<(), JsonError> {
- let mut jb = JsonBuilder::new_array();
+ let mut jb = JsonBuilder::try_new_array().unwrap();
let s = &[0x41, 0x41, 0x41, 0x00];
jb.append_string_from_bytes(s)?;
assert_eq!(jb.buf, r#"["AAA\u0000""#);
let s = &[0x00, 0x01, 0x02, 0x03];
- let mut jb = JsonBuilder::new_array();
+ let mut jb = JsonBuilder::try_new_array().unwrap();
jb.append_string_from_bytes(s)?;
assert_eq!(jb.buf, r#"["\u0000\u0001\u0002\u0003""#);
#[test]
fn test_set_string_from_bytes() {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_string_from_bytes("first", &[]).unwrap();
assert_eq!(jb.buf, r#"{"first":"""#);
jb.set_string_from_bytes("second", &[]).unwrap();
#[test]
fn test_append_string_from_bytes_grow() -> Result<(), JsonError> {
let s = &[0x00, 0x01, 0x02, 0x03];
- let mut jb = JsonBuilder::new_array();
+ let mut jb = JsonBuilder::try_new_array().unwrap();
jb.append_string_from_bytes(s)?;
for i in 1..1000 {
let mut s = Vec::new();
- for _ in 0..i {
- s.push(0x41);
- }
- let mut jb = JsonBuilder::new_array();
+ s.resize(i, 0x41);
+ let mut jb = JsonBuilder::try_new_array().unwrap();
jb.append_string_from_bytes(&s)?;
}
#[test]
fn test_invalid_utf8() {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_string_from_bytes("invalid", &[0xf0, 0xf1, 0xf2])
.unwrap();
assert_eq!(jb.buf, r#"{"invalid":"\\xf0\\xf1\\xf2""#);
- let mut jb = JsonBuilder::new_array();
+ let mut jb = JsonBuilder::try_new_array().unwrap();
jb.append_string_from_bytes(&[0xf0, 0xf1, 0xf2]).unwrap();
assert_eq!(jb.buf, r#"["\\xf0\\xf1\\xf2""#);
}
#[test]
fn test_marks() {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_string("foo", "bar").unwrap();
assert_eq!(jb.buf, r#"{"foo":"bar""#);
assert_eq!(jb.current_state(), State::ObjectNth);
#[test]
fn test_set_formatted() {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_formatted("\"foo\":\"bar\"").unwrap();
assert_eq!(jb.buf, r#"{"foo":"bar""#);
jb.set_formatted("\"bar\":\"foo\"").unwrap();
#[test]
fn test_set_float() {
- let mut jb = JsonBuilder::new_object();
+ let mut jb = JsonBuilder::try_new_object().unwrap();
jb.set_float("one", 1.1).unwrap();
jb.set_float("two", 2.2).unwrap();
jb.close().unwrap();
#[test]
fn test_append_float() {
- let mut jb = JsonBuilder::new_array();
+ let mut jb = JsonBuilder::try_new_array().unwrap();
jb.append_float(1.1).unwrap();
jb.append_float(2.2).unwrap();
jb.close().unwrap();