ion_c_sys/reader.rs
1// Copyright Amazon.com, Inc. or its affiliates.
2
3//! Provides higher-level APIs for Ion C's `hREADER`.
4
5use ion_c_sys_macros::position_error;
6use std::convert::{TryFrom, TryInto};
7use std::marker::PhantomData;
8use std::ops::{Deref, DerefMut};
9use std::os::raw::c_int;
10use std::ptr;
11
12use crate::result::*;
13use crate::string::*;
14use crate::*;
15
16/// The reading API for Ion C.
17///
18/// See also [`IonCReaderHandle`](./struct.IonCReaderHandle.html).
19///
20/// ## Usage
21/// ```
22/// # use ion_c_sys::*;
23/// # use ion_c_sys::reader::*;
24/// # use ion_c_sys::result::*;
25/// # use std::convert::*;
26/// # use std::ptr;
27/// # fn main() -> IonCResult<()> {
28/// let mut reader = IonCReaderHandle::try_from(b"\xE0\x01\x00\xEA\x85hello".as_ref())?;
29/// let tid = reader.next()?;
30/// assert_eq!(ION_TYPE_STRING, tid);
31/// // reader_handle implements Drop, so we're good to go!
32/// # Ok(())
33/// # }
34/// ```
35pub trait IonCReader {
36 /// Advances the reader to the next value and returns the type.
37 fn next(&mut self) -> IonCResult<ION_TYPE>;
38
39 /// Returns the type of the current position.
40 ///
41 /// ## Usage
42 /// ```
43 /// # use std::convert::*;
44 /// # use ion_c_sys::*;
45 /// # use ion_c_sys::reader::*;
46 /// # use ion_c_sys::result::*;
47 /// # fn main() -> IonCResult<()> {
48 /// let mut reader = IonCReaderHandle::try_from("'''hello!'''")?;
49 /// assert_eq!(ION_TYPE_NONE, reader.get_type()?);
50 /// assert_eq!(ION_TYPE_STRING, reader.next()?);
51 /// assert_eq!(ION_TYPE_STRING, reader.get_type()?);
52 /// assert_eq!(ION_TYPE_EOF, reader.next()?);
53 /// assert_eq!(ION_TYPE_EOF, reader.get_type()?);
54 /// # Ok(())
55 /// # }
56 /// ```
57 fn get_type(&self) -> IonCResult<ION_TYPE>;
58
59 /// Steps in to the current container.
60 fn step_in(&mut self) -> IonCResult<()>;
61
62 /// Steps out of the current container.
63 fn step_out(&mut self) -> IonCResult<()>;
64
65 /// Returns the current container depth.
66 ///
67 /// ## Usage
68 /// ```
69 /// # use std::convert::*;
70 /// # use ion_c_sys::*;
71 /// # use ion_c_sys::reader::*;
72 /// # use ion_c_sys::result::*;
73 /// # fn main() -> IonCResult<()> {
74 /// let mut reader = IonCReaderHandle::try_from("[[]]")?;
75 /// assert_eq!(ION_TYPE_LIST, reader.next()?);
76 /// reader.step_in()?;
77 /// assert_eq!(1, reader.depth()?);
78 /// assert_eq!(ION_TYPE_LIST, reader.next()?);
79 /// reader.step_in()?;
80 /// assert_eq!(2, reader.depth()?);
81 /// # Ok(())
82 /// # }
83 /// ```
84 fn depth(&self) -> IonCResult<i32>;
85
86 /// Returns if the reader is positioned on a `null` value.
87 ///
88 /// ## Usage
89 /// ```
90 /// # use std::convert::*;
91 /// # use ion_c_sys::*;
92 /// # use ion_c_sys::reader::*;
93 /// # use ion_c_sys::result::*;
94 /// # fn main() -> IonCResult<()> {
95 /// let mut reader = IonCReaderHandle::try_from("null.int 4")?;
96 /// assert_eq!(ION_TYPE_INT, reader.next()?);
97 /// assert!(reader.is_null()?);
98 /// assert_eq!(ION_TYPE_INT, reader.next()?);
99 /// assert!(!reader.is_null()?);
100 /// # Ok(())
101 /// # }
102 /// ```
103 fn is_null(&self) -> IonCResult<bool>;
104
105 /// Returns if the reader is positioned within a `struct` value.
106 /// ## Usage
107 /// ```
108 /// # use std::convert::*;
109 /// # use ion_c_sys::*;
110 /// # use ion_c_sys::reader::*;
111 /// # use ion_c_sys::result::*;
112 /// # fn main() -> IonCResult<()> {
113 /// let mut reader = IonCReaderHandle::try_from("{}")?;
114 /// assert_eq!(ION_TYPE_STRUCT, reader.next()?);
115 /// assert!(!reader.is_in_struct()?);
116 /// reader.step_in()?;
117 /// assert!(reader.is_in_struct()?);
118 /// # Ok(())
119 /// # }
120 /// ```
121 fn is_in_struct(&self) -> IonCResult<bool>;
122
123 /// Returns the field name if the reader positioned within a structure.
124 ///
125 /// ## Usage
126 /// ```
127 /// # use std::convert::*;
128 /// # use ion_c_sys::*;
129 /// # use ion_c_sys::reader::*;
130 /// # use ion_c_sys::result::*;
131 /// # use ion_c_sys::string::*;
132 /// # fn main() -> IonCResult<()> {
133 /// let mut reader = IonCReaderHandle::try_from("{a:5}")?;
134 /// assert_eq!(ION_TYPE_STRUCT, reader.next()?);
135 /// reader.step_in()?;
136 /// assert_eq!(ION_TYPE_INT, reader.next()?);
137 /// assert_eq!("a", reader.get_field_name()?.as_str());
138 /// # Ok(())
139 /// # }
140 /// ```
141 fn get_field_name(&mut self) -> IonCResult<StrSliceRef>;
142
143 /// Retrieves the annotations associated with the current value.
144 ///
145 /// Note that this allocates a vector on the heap for the `IonCStringRef` instances.
146 /// If this is not desired, use the low-level annotation functions.
147 ///
148 /// ## Usage
149 /// ```
150 /// # use std::convert::*;
151 /// # use ion_c_sys::*;
152 /// # use ion_c_sys::reader::*;
153 /// # use ion_c_sys::result::*;
154 /// # use ion_c_sys::string::*;
155 /// # fn main() -> IonCResult<()> {
156 /// let mut reader = IonCReaderHandle::try_from("ab::cde::fghi::5")?;
157 /// assert_eq!(ION_TYPE_INT, reader.next()?);
158 /// let annotations = reader.get_annotations()?;
159 /// assert_eq!(
160 /// vec!["ab", "cde", "fghi"].as_slice(),
161 /// annotations.as_ref()
162 /// );
163 /// # Ok(())
164 /// # }
165 /// ```
166 fn get_annotations(&mut self) -> IonCResult<StrSlicesRef>;
167
168 /// Reads a `bool` value from the reader.
169 ///
170 /// ## Usage
171 /// ```
172 /// # use std::convert::*;
173 /// # use ion_c_sys::*;
174 /// # use ion_c_sys::reader::*;
175 /// # use ion_c_sys::result::*;
176 /// # fn main() -> IonCResult<()> {
177 /// let mut reader = IonCReaderHandle::try_from("true")?;
178 /// assert_eq!(ION_TYPE_BOOL, reader.next()?);
179 /// assert!(reader.read_bool()?);
180 /// # Ok(())
181 /// # }
182 /// ```
183 fn read_bool(&mut self) -> IonCResult<bool>;
184
185 /// Reads an `int` value from the reader.
186 ///
187 /// ## Usage
188 /// ```
189 /// # use std::convert::*;
190 /// # use ion_c_sys::*;
191 /// # use ion_c_sys::reader::*;
192 /// # use ion_c_sys::result::*;
193 /// # fn main() -> IonCResult<()> {
194 /// let mut reader = IonCReaderHandle::try_from("42")?;
195 /// assert_eq!(ION_TYPE_INT, reader.next()?);
196 /// assert_eq!(42, reader.read_i64()?);
197 /// # Ok(())
198 /// # }
199 /// ```
200 fn read_i64(&mut self) -> IonCResult<i64>;
201
202 /// Reads an `int` value from the reader as a `BigInt`.
203 ///
204 /// ## Usage
205 /// ```
206 /// # use std::convert::*;
207 /// # use ion_c_sys::*;
208 /// # use ion_c_sys::reader::*;
209 /// # use ion_c_sys::result::*;
210 /// # use num_bigint::BigInt;
211 /// # fn main() -> IonCResult<()> {
212 /// let mut reader = IonCReaderHandle::try_from("0x5195a4b154400e07dee3a7378c403b2d5dd6dd58735")?;
213 /// assert_eq!(ION_TYPE_INT, reader.next()?);
214 /// assert_eq!(
215 /// BigInt::parse_bytes(b"1907775120294590714755986204580814176547217067050805", 10).unwrap(),
216 /// reader.read_bigint()?
217 /// );
218 /// # Ok(())
219 /// # }
220 /// ```
221 fn read_bigint(&mut self) -> IonCResult<BigInt>;
222
223 /// Reads a `float` value from the reader.
224 ///
225 /// ## Usage
226 /// ```
227 /// # use std::convert::*;
228 /// # use ion_c_sys::*;
229 /// # use ion_c_sys::reader::*;
230 /// # use ion_c_sys::result::*;
231 /// # fn main() -> IonCResult<()> {
232 /// let mut reader = IonCReaderHandle::try_from("3.0e0")?;
233 /// assert_eq!(ION_TYPE_FLOAT, reader.next()?);
234 /// assert_eq!(3.0, reader.read_f64()?);
235 /// # Ok(())
236 /// # }
237 /// ```
238 fn read_f64(&mut self) -> IonCResult<f64>;
239
240 /// Reads a `bigdecimal` value from the reader.
241 ///
242 /// ## Usage
243 /// ```
244 /// # use std::convert::*;
245 /// # use bigdecimal::BigDecimal;
246 /// # use ion_c_sys::*;
247 /// # use ion_c_sys::decimal::*;
248 /// # use ion_c_sys::reader::*;
249 /// # use ion_c_sys::result::*;
250 /// # fn main() -> IonCResult<()> {
251 /// let mut reader = IonCReaderHandle::try_from("3.0")?;
252 /// assert_eq!(ION_TYPE_DECIMAL, reader.next()?);
253 /// let value = BigDecimal::parse_bytes(b"30E-1", 10).unwrap();
254 /// assert_eq!(value, reader.read_bigdecimal()?);
255 /// # Ok(())
256 /// # }
257 /// ```
258 fn read_bigdecimal(&mut self) -> IonCResult<BigDecimal>;
259
260 /// Reads a `timestamp` value from the reader.
261 ///
262 /// ## Usage
263 /// ```
264 /// # use std::convert::*;
265 /// # use ion_c_sys::*;
266 /// # use chrono::DateTime;
267 /// # use ion_c_sys::timestamp::*;
268 /// # use ion_c_sys::timestamp::Mantissa::*;
269 /// # use ion_c_sys::timestamp::TSPrecision::*;
270 /// # use ion_c_sys::timestamp::TSOffsetKind::*;
271 /// # use ion_c_sys::reader::*;
272 /// # use ion_c_sys::result::*;
273 /// # fn main() -> IonCResult<()> {
274 /// let mut reader = IonCReaderHandle::try_from("2020-10-10T12:34:45.123-00:00")?;
275 /// assert_eq!(ION_TYPE_TIMESTAMP, reader.next()?);
276 /// let ion_dt = reader.read_datetime()?;
277 ///
278 /// // the point in time should be the same
279 /// let expected_dt = DateTime::parse_from_rfc3339("2020-10-10T12:34:45.123Z").unwrap();
280 /// assert_eq!(&expected_dt, ion_dt.as_datetime());
281 ///
282 /// // precision should be millisecond level
283 /// if let Fractional(Digits(digits)) = ion_dt.precision() {
284 /// assert_eq!(3, *digits);
285 /// } else {
286 /// assert!(false, "Expected digits precision!");
287 /// }
288 ///
289 /// // we should have an unknown offset
290 /// assert_eq!(UnknownOffset, ion_dt.offset_kind());
291 /// # Ok(())
292 /// # }
293 /// ```
294 fn read_datetime(&mut self) -> IonCResult<IonDateTime>;
295
296 /// Reads a `string`/`symbol` value from the reader.
297 ///
298 /// ## Usage
299 /// ```
300 /// # use std::convert::*;
301 /// # use ion_c_sys::*;
302 /// # use ion_c_sys::reader::*;
303 /// # use ion_c_sys::result::*;
304 /// # fn main() -> IonCResult<()> {
305 /// let mut reader = IonCReaderHandle::try_from("\"🦄\" '✨'")?;
306 /// assert_eq!(ION_TYPE_STRING, reader.next()?);
307 /// assert_eq!("🦄", reader.read_string()?.as_str());
308 /// assert_eq!(ION_TYPE_SYMBOL, reader.next()?);
309 /// assert_eq!("✨", reader.read_string()?.as_str());
310 /// # Ok(())
311 /// # }
312 /// ```
313 fn read_string(&mut self) -> IonCResult<StrSliceRef>;
314
315 /// Reads a `clob`/`blob` value from the reader.
316 ///
317 /// This method implements a vector on the heap to store a copy of the LOB.
318 /// If this is not desired, use the low-level length and read methods directly.
319 ///
320 /// ## Usage
321 /// ```
322 /// # use std::convert::*;
323 /// # use ion_c_sys::*;
324 /// # use ion_c_sys::reader::*;
325 /// # use ion_c_sys::result::*;
326 /// # fn main() -> IonCResult<()> {
327 /// let mut reader = IonCReaderHandle::try_from("{{\"hello\"}} {{d29ybGQ=}} {{}}")?;
328 /// assert_eq!(ION_TYPE_CLOB, reader.next()?);
329 /// assert_eq!(b"hello", reader.read_bytes()?.as_slice());
330 /// assert_eq!(ION_TYPE_BLOB, reader.next()?);
331 /// assert_eq!(b"world", reader.read_bytes()?.as_slice());
332 /// assert_eq!(ION_TYPE_BLOB, reader.next()?);
333 /// assert_eq!(b"", reader.read_bytes()?.as_slice());
334 /// # Ok(())
335 /// # }
336 /// ```
337 fn read_bytes(&mut self) -> IonCResult<Vec<u8>>;
338
339 /// Returns the current position. TODO: blah blah.
340 fn pos(&self) -> IonCResult<Position>;
341}
342
343/// Wrapper over `hREADER` to make it easier to use readers in IonC correctly.
344///
345/// Specifically supports the `Drop` trait to make sure `ion_reader_close` is run.
346/// Access to the underlying `hREADER` pointer is done by de-referencing the handle.
347pub struct IonCReaderHandle<'a> {
348 reader: hREADER,
349 /// Placeholder to tie our lifecycle back to the source of the data--which might not
350 /// actually be a byte slice (if we constructed this from a file or Ion C stream callback)
351 referent: PhantomData<&'a [u8]>,
352}
353
354impl<'a> IonCReaderHandle<'a> {
355 /// Constructs a reader handle from a byte slice and given options.
356 pub fn try_from_buf(
357 src: &'a [u8],
358 options: &mut ION_READER_OPTIONS,
359 ) -> Result<Self, IonCError> {
360 let mut reader = ptr::null_mut();
361 ionc!(ion_reader_open_buffer(
362 &mut reader,
363 // Ion C promises not to mutate this buffer!
364 src.as_ptr() as *mut u8,
365 src.len().try_into()?,
366 options,
367 ))?;
368 Ok(IonCReaderHandle {
369 reader,
370 referent: PhantomData::default(),
371 })
372 }
373}
374impl<'a> IonCReader for IonCReaderHandle<'a> {
375 #[position_error]
376 #[inline]
377 fn next(&mut self) -> IonCResult<ION_TYPE> {
378 let mut tid = ptr::null_mut();
379 ionc!(ion_reader_next(self.reader, &mut tid))?;
380
381 Ok(tid)
382 }
383
384 #[position_error]
385 #[inline]
386 fn get_type(&self) -> IonCResult<ION_TYPE> {
387 let mut tid = ptr::null_mut();
388 ionc!(ion_reader_get_type(self.reader, &mut tid))?;
389
390 Ok(tid)
391 }
392
393 #[position_error]
394 #[inline]
395 fn step_in(&mut self) -> IonCResult<()> {
396 ionc!(ion_reader_step_in(self.reader))
397 }
398
399 #[position_error]
400 #[inline]
401 fn step_out(&mut self) -> IonCResult<()> {
402 ionc!(ion_reader_step_out(self.reader))
403 }
404
405 #[position_error]
406 #[inline]
407 fn depth(&self) -> IonCResult<i32> {
408 let mut depth = 0;
409 ionc!(ion_reader_get_depth(self.reader, &mut depth))?;
410
411 Ok(depth)
412 }
413
414 #[position_error]
415 #[inline]
416 fn is_null(&self) -> IonCResult<bool> {
417 let mut is_null = 0;
418 ionc!(ion_reader_is_null(self.reader, &mut is_null))?;
419
420 Ok(is_null != 0)
421 }
422
423 #[position_error]
424 #[inline]
425 fn is_in_struct(&self) -> IonCResult<bool> {
426 let mut is_in_struct = 0;
427 ionc!(ion_reader_is_in_struct(self.reader, &mut is_in_struct))?;
428
429 Ok(is_in_struct != 0)
430 }
431
432 #[position_error]
433 #[inline]
434 fn get_field_name(&mut self) -> IonCResult<StrSliceRef> {
435 let mut field = ION_STRING::default();
436 ionc!(ion_reader_get_field_name(self.reader, &mut field))?;
437
438 // make a str slice that is tied to our lifetime
439 let field_str = field.as_str(PhantomData::<&'a u8>::default())?;
440 Ok(StrSliceRef::new(self, field_str))
441 }
442
443 fn get_annotations(&mut self) -> IonCResult<StrSlicesRef> {
444 // determine how many annotations are available
445 let mut raw_len = 0;
446 ionc!(ion_reader_get_annotation_count(self.reader, &mut raw_len))?;
447
448 let len: usize = raw_len.try_into()?;
449 let mut annotations = Vec::new();
450 let mut curr = ION_STRING::default();
451 for i in 0..len {
452 ionc!(ion_reader_get_an_annotation(
453 self.reader,
454 i as c_int,
455 &mut curr
456 ))?;
457 // make a str slice that is tied to our lifetime
458 annotations.push(curr.as_str(PhantomData::<&'a u8>::default())?);
459 }
460
461 Ok(StrSlicesRef::new(self, annotations))
462 }
463
464 #[position_error]
465 #[inline]
466 fn read_bool(&mut self) -> IonCResult<bool> {
467 let mut value = 0;
468 ionc!(ion_reader_read_bool(self.reader, &mut value))?;
469
470 Ok(value != 0)
471 }
472
473 #[position_error]
474 #[inline]
475 fn read_i64(&mut self) -> IonCResult<i64> {
476 let mut value = 0;
477 ionc!(ion_reader_read_int64(self.reader, &mut value))?;
478
479 Ok(value)
480 }
481
482 #[position_error]
483 #[inline]
484 fn read_bigint(&mut self) -> IonCResult<BigInt> {
485 let mut value = ION_INT::default();
486 ionc!(ion_reader_read_ion_int(self.reader, &mut value))?;
487
488 value.try_to_bigint()
489 }
490
491 #[position_error]
492 #[inline]
493 fn read_f64(&mut self) -> IonCResult<f64> {
494 let mut value = 0.0;
495 ionc!(ion_reader_read_double(self.reader, &mut value))?;
496
497 Ok(value)
498 }
499
500 #[position_error]
501 #[inline]
502 fn read_bigdecimal(&mut self) -> IonCResult<BigDecimal> {
503 let mut value = ION_DECIMAL::default();
504 ionc!(ion_reader_read_ion_decimal(self.reader, &mut value))?;
505
506 value.try_to_bigdecimal()
507 }
508
509 #[position_error]
510 #[inline]
511 fn read_datetime(&mut self) -> IonCResult<IonDateTime> {
512 let mut value = ION_TIMESTAMP::default();
513 ionc!(ion_reader_read_timestamp(self.reader, &mut value))?;
514
515 value.try_to_iondt()
516 }
517
518 #[position_error]
519 #[inline]
520 fn read_string(&mut self) -> IonCResult<StrSliceRef> {
521 let mut value = ION_STRING::default();
522 ionc!(ion_reader_read_string(self.reader, &mut value))?;
523
524 // make a str slice that is tied to our lifetime
525 let str_ref = value.as_str(PhantomData::<&'a u8>::default())?;
526 Ok(StrSliceRef::new(self, str_ref))
527 }
528
529 #[position_error]
530 #[inline]
531 fn read_bytes(&mut self) -> IonCResult<Vec<u8>> {
532 let mut len = 0;
533 ionc!(ion_reader_get_lob_size(self.reader, &mut len))?;
534 if len == 0 {
535 // XXX short-circuit the empty case
536 // until amzn/ion-c#233 is fixed this will panic, but there
537 // is no reason to call into Ion C in this case anyhow
538 return Ok(Vec::new());
539 }
540
541 let mut read_len = 0;
542 let mut buf = vec![0; len.try_into()?];
543 ionc!(ion_reader_read_lob_bytes(
544 self.reader,
545 buf.as_mut_ptr(),
546 buf.len().try_into()?,
547 &mut read_len
548 ))?;
549 if len != read_len {
550 Err(IonCError::from(ion_error_code_IERR_INVALID_STATE))
551 } else {
552 Ok(buf)
553 }
554 }
555
556 // *NOT* annotated with `#[position_error]` - if reading the current
557 // position is an error, then we don't want to include the position in the
558 // error!
559 //
560 // This method is actually implemented in `reader_current_pos`. Otherwise,
561 // various reader trait methods require additional borrows.
562 #[inline]
563 fn pos(&self) -> IonCResult<Position> {
564 reader_current_pos(&self.reader)
565 }
566}
567
568/// Asks `reader` for its current position and includes it in `err`.
569///
570/// If the position is already known, then this method does nothing. If reading
571/// the position returns an error, then this method also does nothing!
572///
573/// This method is defined on the reader handle directly because of partial
574/// borrow requirements in the implementation of the `Reader` trait.
575pub fn include_current_position(reader: &hREADER, err: IonCError) -> IonCError {
576 if !std::matches!(err.position, Position::Unknown) {
577 return err;
578 }
579
580 let pos = match reader_current_pos(reader) {
581 Ok(pos) => pos,
582 Err(_) => return err, // the original, not the one from failing to read the pos
583 };
584
585 err.with_position(pos)
586}
587
588#[inline]
589fn reader_current_pos(reader: &hREADER) -> IonCResult<Position> {
590 let mut bytes: i64 = -1;
591 let mut line = -1;
592 let mut offset = -1;
593 ionc!(ion_reader_get_position(
594 *reader,
595 &mut bytes,
596 &mut line,
597 &mut offset
598 ))?;
599
600 Ok(match (bytes, line, offset) {
601 (b, -1, -1) if b > 0 => Position::Offset(b),
602 (b, l, o) if b > 0 && l > 0 && o > 0 => Position::OffsetLineColumn(b, LineColumn(l, o)),
603 // Should never happen!
604 _ => Position::Unknown,
605 })
606}
607
608impl<'a> TryFrom<&'a [u8]> for IonCReaderHandle<'a> {
609 type Error = IonCError;
610
611 /// Constructs a reader from a byte slice with the default options.
612 #[inline]
613 fn try_from(src: &'a [u8]) -> Result<Self, Self::Error> {
614 Self::try_from_buf(src, &mut ION_READER_OPTIONS::default())
615 }
616}
617
618impl<'a> TryFrom<&'a str> for IonCReaderHandle<'a> {
619 type Error = IonCError;
620 /// Constructs a reader from a str slice with the default options.
621 #[inline]
622 fn try_from(src: &'a str) -> Result<Self, Self::Error> {
623 Self::try_from(src.as_bytes())
624 }
625}
626
627impl Deref for IonCReaderHandle<'_> {
628 type Target = hREADER;
629
630 #[inline]
631 fn deref(&self) -> &Self::Target {
632 &self.reader
633 }
634}
635
636impl DerefMut for IonCReaderHandle<'_> {
637 #[inline]
638 fn deref_mut(&mut self) -> &mut Self::Target {
639 &mut self.reader
640 }
641}
642
643impl Drop for IonCReaderHandle<'_> {
644 fn drop(&mut self) {
645 if !self.reader.is_null() {
646 ionc!(ion_reader_close(self.reader)).unwrap()
647 }
648 }
649}
650
651#[cfg(test)]
652mod reader_tests {
653 use super::*;
654
655 #[test]
656 fn position_error() -> IonCResult<()> {
657 let data = r#"{foo:"bar",baz:"#;
658 let mut reader = IonCReaderHandle::try_from(data)?;
659 reader.next()?;
660
661 // `baz` has a field but not value - boom!
662 let err = match reader.next() {
663 Err(e) => e,
664 Ok(t) => panic!("expected an error, found a {:?}", t),
665 };
666
667 assert_eq!(err.position, Position::text(15, 1, 16));
668
669 Ok(())
670 }
671}