1use std::io;
4use std::io::{ Read, BufReader };
5use std::fmt::Debug;
6use std::result;
7
8use std::io::{ BufRead, Result, ErrorKind };
9
10mod ply_grammar;
11
12use self::ply_grammar::grammar;
13use self::ply_grammar::Line;
14use crate::util::LocationTracker;
15
16fn parse_ascii_rethrow<T, E: Debug>(location: &LocationTracker, line_str: &str, e: E, message: &str) -> Result<T> {
17 Err(io::Error::new(
18 ErrorKind::InvalidInput,
19 format!("Line {}: {}\n\tString: '{}'\n\tError: {:?}", location.line_index, message, line_str, e)
20 ))
21}
22fn parse_ascii_error<T>(location: &LocationTracker, line_str: &str, message: &str) -> Result<T> {
23 Err(io::Error::new(
24 ErrorKind::InvalidInput,
25 format!("Line {}: {}\n\tString: '{}'", location.line_index, message, line_str)
26 ))
27}
28
29use std::marker::PhantomData;
30
31pub struct Parser<E: PropertyAccess> {
94 phantom: PhantomData<E>,
95}
96
97
98use crate::ply::Ply;
101use crate::ply::{ Header, Payload, Encoding };
102
103impl<E: PropertyAccess> Parser<E> {
104 pub fn new() -> Self {
108 Parser {
109 phantom: PhantomData
110 }
111 }
112
113 pub fn read_ply<T: Read>(&self, source: &mut T) -> Result<Ply<E>> {
118 let mut source = BufReader::new(source);
119 let mut location = LocationTracker::new();
120 let header = self.__read_header(&mut source, &mut location)?;
121 let payload = self.__read_payload(&mut source, &mut location, &header)?;
122 let mut ply = Ply::new();
123 ply.header = header;
124 ply.payload = payload;
125 Ok(ply)
126 }
127}
128
129use crate::ply::{ PropertyAccess, Version, ObjInfo, Comment, ElementDef, KeyMap, Addable };
131impl<E: PropertyAccess> Parser<E> {
146 pub fn read_header<T: BufRead>(&self, reader: &mut T) -> Result<Header> {
151 let mut line = LocationTracker::new();
152 self.__read_header(reader, &mut line)
153 }
154 pub fn read_header_line(&self, line: &str) -> Result<Line> {
155 match self.__read_header_line(line) {
156 Ok(l) => Ok(l),
157 Err(e) => Err(io::Error::new(
158 ErrorKind::InvalidInput,
159 format!("Couldn't parse line.\n\tString: {}\n\tError: {:?}", line, e)
160 )),
161 }
162 }
163
164 fn __read_header_line(&self, line_str: &str) -> result::Result<Line, peg::error::ParseError<peg::str::LineCol>> {
166 grammar::line(line_str)
167 }
168 fn __read_header<T: BufRead>(&self, reader: &mut T, location: &mut LocationTracker) -> Result<Header> {
169 location.next_line();
170 let mut line_str = String::new();
171 reader.read_line(&mut line_str)?;
172 match self.__read_header_line(&line_str) {
173 Ok(Line::MagicNumber) => (),
174 Ok(l) => return parse_ascii_error(location, &line_str, &format!("Expected magic number 'ply', but saw '{:?}'.", l)),
175 Err(e) => return parse_ascii_rethrow(location, &line_str, e, "Expected magic number 'ply'.")
176 }
177 match grammar::line(&line_str) {
178 Err(e) => return Err(io::Error::new(ErrorKind::InvalidInput, e)),
179 Ok(l @ Line::MagicNumber) => (l),
180 Ok(ob) => return Err(io::Error::new(
181 ErrorKind::InvalidInput,
182 format!("Invalid line encountered. Expected type: 'Line::MagicNumber', found: '{:?}'", ob)
183 )),
184 };
185
186 let mut header_form_ver : Option<(Encoding, Version)> = None;
187 let mut header_obj_infos = Vec::<ObjInfo>::new();
188 let mut header_elements = KeyMap::<ElementDef>::new();
189 let mut header_comments = Vec::<Comment>::new();
190 location.next_line();
191 'readlines: loop {
192 line_str.clear();
193 reader.read_line(&mut line_str)?;
194 let line = self.__read_header_line(&line_str);
195
196 match line {
197 Err(e) => return parse_ascii_rethrow(location, &line_str, e, "Couldn't parse line."),
198 Ok(Line::MagicNumber) => return parse_ascii_error(location, &line_str, "Unexpected 'ply' found."),
199 Ok(Line::Format(ref t)) => (
200 if header_form_ver.is_none() {
201 header_form_ver = Some(t.clone());
202 } else {
203 let f = header_form_ver.unwrap();
204 if f != *t {
205 return parse_ascii_error(
206 location,
207 &line_str,
208 &format!(
209 "Found contradicting format definition:\n\
210 \tEncoding: {:?}, Version: {:?}\n\
211 previous definition:\n\
212 \tEncoding: {:?}, Version: {:?}",
213 t.0, t.1, f.0, f.1)
214 )
215 }
216 }
217 ),
218 Ok(Line::ObjInfo(ref o)) => (
219 header_obj_infos.push(o.clone())
220 ),
221 Ok(Line::Comment(ref c)) => (
222 header_comments.push(c.clone())
223 ),
224 Ok(Line::Element(ref e)) => {
225 header_elements.add(e.clone())
226 },
227 Ok(Line::Property(p)) => (
228 if header_elements.is_empty() {
229 return parse_ascii_error(
230 location,
231 &line_str,
232 &format!("Property '{:?}' found without preceding element.", p)
233 );
234 } else {
235 let (_, mut e) = header_elements.pop_back().unwrap();
236 e.properties.add(p);
237 header_elements.add(e);
238 }
239 ),
240 Ok(Line::EndHeader) => { location.next_line(); break 'readlines; },
241 };
242 location.next_line();
243 }
244 if header_form_ver.is_none() {
245 return Err(io::Error::new(
246 ErrorKind::InvalidInput,
247 "No format line found."
248 ));
249 }
250 let (encoding, version) = header_form_ver.unwrap();
251 Ok(Header{
252 encoding: encoding,
253 version: version,
254 obj_infos: header_obj_infos,
255 comments: header_comments,
256 elements: header_elements
257 })
258 }
259}
260
261impl<E: PropertyAccess> Parser<E> {
266 pub fn read_payload<T: BufRead>(&self, reader: &mut T, header: &Header) -> Result<Payload<E>> {
268 let mut location = LocationTracker::new();
269 self.__read_payload(reader, &mut location, header)
270 }
271 pub fn read_payload_for_element<T: BufRead>(&self, reader: &mut T, element_def: &ElementDef, header: &Header) -> Result<Vec<E>> {
275 let mut location = LocationTracker::new();
276 match header.encoding {
277 Encoding::Ascii => self.__read_ascii_payload_for_element(reader, &mut location, element_def),
278 Encoding::BinaryBigEndian => self.__read_big_endian_payload_for_element(reader, &mut location, element_def),
279 Encoding::BinaryLittleEndian => self.__read_little_endian_payload_for_element(reader, &mut location, element_def),
280 }
281 }
282 fn __read_payload<T: BufRead>(&self, reader: &mut T, location: &mut LocationTracker, header: &Header) -> Result<Payload<E>> {
284 let mut payload = Payload::new();
285 match header.encoding {
286 Encoding::Ascii => for (k, ref e) in &header.elements {
287 let elems = self.__read_ascii_payload_for_element(reader, location, e)?;
288 payload.insert(k.clone(), elems);
289 },
290 Encoding::BinaryBigEndian => for (k, ref e) in &header.elements {
291 let elems = self.__read_big_endian_payload_for_element(reader, location, e)?;
292 payload.insert(k.clone(), elems);
293 },
294 Encoding::BinaryLittleEndian => for (k, ref e) in &header.elements {
295 let elems = self.__read_little_endian_payload_for_element(reader, location, e)?;
296 payload.insert(k.clone(), elems);
297 }
298 }
299 Ok(payload)
300 }
301}
302
303
304
305use std::slice::Iter;
320use std::str::FromStr;
321
322use crate::ply::{ Property, PropertyType, ScalarType };
323use std::error;
324use std::marker;
325
326impl<E: PropertyAccess> Parser<E> {
328 fn __read_ascii_payload_for_element<T: BufRead>(&self, reader: &mut T, location: &mut LocationTracker, element_def: &ElementDef) -> Result<Vec<E>> {
329 let mut elems = Vec::<E>::new();
330 let mut line_str = String::new();
331 for _ in 0..element_def.count {
332 line_str.clear();
333 reader.read_line(&mut line_str)?;
334
335 let element = match self.read_ascii_element(&line_str, element_def) {
336 Ok(e) => e,
337 Err(e) => return parse_ascii_rethrow(location, &line_str, e, "Couln't read element line.")
338 };
339 elems.push(element);
340 location.next_line();
341 }
342 Ok(elems)
343 }
344 pub fn read_ascii_element(&self, line: &str, element_def: &ElementDef) -> Result<E> {
348 let elems = match grammar::data_line(line) {
349 Ok(e) => e,
350 Err(ref e) => return Err(io::Error::new(
351 ErrorKind::InvalidInput,
352 format!("Couldn't parse element line.\n\tString: '{}'\n\tError: {}", line, e)
353 )),
354 };
355
356 let mut elem_it : Iter<String> = elems.iter();
357 let mut vals = E::new();
358 for (k, p) in &element_def.properties {
359 let new_p : Property = self.__read_ascii_property(&mut elem_it, &p.data_type)?;
360 vals.set_property(k.clone(), new_p);
361 }
362 Ok(vals)
363 }
364 fn __read_ascii_property(&self, elem_iter: &mut Iter<String>, data_type: &PropertyType) -> Result<Property> {
365 let s : &String = match elem_iter.next() {
366 None => return Err(io::Error::new(
367 ErrorKind::InvalidInput,
368 format!("Expected element of type '{:?}', but found nothing.", data_type)
369 )),
370 Some(x) => x
371 };
372
373 let result = match *data_type {
374 PropertyType::Scalar(ref scalar_type) => match *scalar_type {
375 ScalarType::Char => Property::Char(self.parse(s)?),
376 ScalarType::UChar => Property::UChar(self.parse(s)?),
377 ScalarType::Short => Property::Short(self.parse(s)?),
378 ScalarType::UShort => Property::UShort(self.parse(s)?),
379 ScalarType::Int => Property::Int(self.parse(s)?),
380 ScalarType::UInt => Property::UInt(self.parse(s)?),
381 ScalarType::Float => Property::Float(self.parse(s)?),
382 ScalarType::Double => Property::Double(self.parse(s)?),
383 },
384 PropertyType::List(_, ref scalar_type) => {
385 let count : usize = self.parse(s)?;
386 match *scalar_type {
387 ScalarType::Char => Property::ListChar(self.__read_ascii_list(elem_iter, count)?),
388 ScalarType::UChar => Property::ListUChar(self.__read_ascii_list(elem_iter, count)?),
389 ScalarType::Short => Property::ListShort(self.__read_ascii_list(elem_iter, count)?),
390 ScalarType::UShort => Property::ListUShort(self.__read_ascii_list(elem_iter, count)?),
391 ScalarType::Int => Property::ListInt(self.__read_ascii_list(elem_iter, count)?),
392 ScalarType::UInt => Property::ListUInt(self.__read_ascii_list(elem_iter, count)?),
393 ScalarType::Float => Property::ListFloat(self.__read_ascii_list(elem_iter, count)?),
394 ScalarType::Double => Property::ListDouble(self.__read_ascii_list(elem_iter, count)?),
395 }
396 }
397 };
398 Ok(result)
399 }
400
401 fn parse<D: FromStr>(&self, s: &str) -> Result<D>
402 where <D as FromStr>::Err: error::Error + Send + Sync + 'static {
403 let v = s.parse();
404 match v {
405 Ok(r) => Ok(r),
406 Err(e) => Err(io::Error::new(ErrorKind::InvalidInput,
407 format!("Parse error.\n\tValue: '{}'\n\tError: {:?}, ", s, e))),
408 }
409 }
410 fn __read_ascii_list<D: FromStr>(&self, elem_iter: &mut Iter<String>, count: usize) -> Result<Vec<D>>
411 where <D as FromStr>::Err: error::Error + marker::Send + marker::Sync + 'static {
412 let mut list = Vec::<D>::new();
413 for i in 0..count {
414 let s : &String = match elem_iter.next() {
415 None => return Err(io::Error::new(
416 ErrorKind::InvalidInput,
417 format!("Couldn't find a list element at index {}.", i)
418 )),
419 Some(x) => x
420 };
421 let value : D = self.parse(s)?;
422 list.push(value);
423 }
424 Ok(list)
425 }
426}
427
428use byteorder::{ BigEndian, LittleEndian, ReadBytesExt, ByteOrder };
442use peg;
443
444impl<E: PropertyAccess> Parser<E> {
446 pub fn read_big_endian_element<T: Read>(&self, reader: &mut T, element_def: &ElementDef) -> Result<E> {
450 self.__read_binary_element::<T, BigEndian>(reader, element_def)
452 }
453 pub fn read_little_endian_element<T: Read>(&self, reader: &mut T, element_def: &ElementDef) -> Result<E> {
457 self.__read_binary_element::<T, LittleEndian>(reader, element_def)
459 }
460
461 fn __read_big_endian_payload_for_element<T: Read>(&self, reader: &mut T, location: &mut LocationTracker, element_def: &ElementDef) -> Result<Vec<E>> {
463 self.__read_binary_payload_for_element::<T, BigEndian>(reader, location, element_def)
464 }
465 fn __read_little_endian_payload_for_element<T: Read>(&self, reader: &mut T, location: &mut LocationTracker, element_def: &ElementDef) -> Result<Vec<E>> {
466 self.__read_binary_payload_for_element::<T, LittleEndian>(reader, location, element_def)
467 }
468
469 fn __read_binary_payload_for_element<T: Read, B: ByteOrder>(&self, reader: &mut T, location: &mut LocationTracker, element_def: &ElementDef) -> Result<Vec<E>> {
470 let mut elems = Vec::<E>::new();
471 for _ in 0..element_def.count {
472 let element = self.__read_binary_element::<T, B>(reader, element_def)?;
473 elems.push(element);
474 location.next_line();
475 }
476 Ok(elems)
477 }
478 fn __read_binary_element<T: Read, B: ByteOrder>(&self, reader: &mut T, element_def: &ElementDef) -> Result<E> {
479 let mut raw_element = E::new();
480
481 for (k, p) in &element_def.properties {
482 let property = self.__read_binary_property::<T, B>(reader, &p.data_type)?;
483 raw_element.set_property(k.clone(), property);
484 }
485 Ok(raw_element)
486 }
487 fn __read_binary_property<T: Read, B: ByteOrder>(&self, reader: &mut T, data_type: &PropertyType) -> Result<Property> {
488 let result = match *data_type {
489 PropertyType::Scalar(ref scalar_type) => match *scalar_type {
490 ScalarType::Char => Property::Char(reader.read_i8()?),
491 ScalarType::UChar => Property::UChar(reader.read_u8()?),
492 ScalarType::Short => Property::Short(reader.read_i16::<B>()?),
493 ScalarType::UShort => Property::UShort(reader.read_u16::<B>()?),
494 ScalarType::Int => Property::Int(reader.read_i32::<B>()?),
495 ScalarType::UInt => Property::UInt(reader.read_u32::<B>()?),
496 ScalarType::Float => Property::Float(reader.read_f32::<B>()?),
497 ScalarType::Double => Property::Double(reader.read_f64::<B>()?),
498 },
499 PropertyType::List(ref index_type, ref property_type) => {
500 let count : usize = match *index_type {
501 ScalarType::Char => reader.read_i8()? as usize,
502 ScalarType::UChar => reader.read_u8()? as usize,
503 ScalarType::Short => reader.read_i16::<B>()? as usize,
504 ScalarType::UShort => reader.read_u16::<B>()? as usize,
505 ScalarType::Int => reader.read_i32::<B>()? as usize,
506 ScalarType::UInt => reader.read_u32::<B>()? as usize,
507 ScalarType::Float => return Err(io::Error::new(ErrorKind::InvalidInput, "Index of list must be an integer type, float declared in ScalarType.")),
508 ScalarType::Double => return Err(io::Error::new(ErrorKind::InvalidInput, "Index of list must be an integer type, double declared in ScalarType.")),
509 };
510 match *property_type {
511 ScalarType::Char => Property::ListChar(self.__read_binary_list(reader, &|r| r.read_i8(), count)?),
512 ScalarType::UChar => Property::ListUChar(self.__read_binary_list(reader, &|r| r.read_u8(), count)?),
513 ScalarType::Short => Property::ListShort(self.__read_binary_list(reader, &|r| r.read_i16::<B>(), count)?),
514 ScalarType::UShort => Property::ListUShort(self.__read_binary_list(reader, &|r| r.read_u16::<B>(), count)?),
515 ScalarType::Int => Property::ListInt(self.__read_binary_list(reader, &|r| r.read_i32::<B>(), count)?),
516 ScalarType::UInt => Property::ListUInt(self.__read_binary_list(reader, &|r| r.read_u32::<B>(), count)?),
517 ScalarType::Float => Property::ListFloat(self.__read_binary_list(reader, &|r| r.read_f32::<B>(), count)?),
518 ScalarType::Double => Property::ListDouble(self.__read_binary_list(reader, &|r| r.read_f64::<B>(), count)?),
519 }
520 }
521 };
522 Ok(result)
523 }
524 fn __read_binary_list<T: Read, D: FromStr>(&self, reader: &mut T, read_from: &dyn Fn(&mut T) -> Result<D>, count: usize) -> Result<Vec<D>>
525 where <D as FromStr>::Err: error::Error + marker::Send + marker::Sync + 'static {
526 let mut list = Vec::<D>::new();
527 for i in 0..count {
528 let value : D = match read_from(reader) {
529 Err(e) => return Err(io::Error::new(
530 ErrorKind::InvalidInput,
531 format!("Couldn't find a list element at index {}.\n\tError: {:?}", i, e)
532 )),
533 Ok(x) => x
534 };
535 list.push(value);
536 }
537 Ok(list)
538 }
539}
540
541
542
543#[cfg(test)]
544mod tests {
545 use super::grammar as g;
546 use super::Line;
547 use crate::parser::Parser;
548 use crate::ply::{ DefaultElement, PropertyDef, Version, Encoding, ScalarType, PropertyType, ElementDef, KeyMap, Addable };
549 macro_rules! assert_ok {
550 ($e:expr) => (
551 match $e {
552 Ok(obj) => (obj),
553 Err(e) => panic!("{}", e),
554 }
555 );
556 ($e:expr , $o:expr) => (
557 let obj = assert_ok!($e);
558 assert_eq!(obj, $o);
559 );
560 }
561 macro_rules! assert_err {
562 ($e:expr) => (
563 let result = $e;
564 assert!(result.is_err());
565 );
566 }
567 #[test]
568 fn parser_header_ok(){
569 let p = Parser::<DefaultElement>::new();
570 let txt = "ply\nformat ascii 1.0\nend_header\n";
571 let mut bytes = txt.as_bytes();
572 assert_ok!(p.read_header(&mut bytes));
573
574 let txt = "ply\n\
575 format ascii 1.0\n\
576 element vertex 8\n\
577 property float x\n\
578 property float y\n\
579 element face 6\n\
580 property list uchar int vertex_index\n\
581 end_header\n";
582 let mut bytes = txt.as_bytes();
583 assert_ok!(p.read_header(&mut bytes));
584 }
585 #[test]
586 fn parser_demo_ok(){
587 let txt = "ply\nformat ascii 1.0\nend_header\n";
588 let mut bytes = txt.as_bytes();
589 let p = Parser::<DefaultElement>::new();
590 assert_ok!(p.read_header(&mut bytes));
591
592 let txt = "ply\n\
593 format ascii 1.0\n\
594 element vertex 1\n\
595 property float x\n\
596 end_header\n
597 6.28318530718"; let mut bytes = txt.as_bytes();
599 assert_ok!(p.read_header(&mut bytes));
600 }
601 #[test]
602 fn parser_single_elements_ok(){
603 let txt = "ply\r\n\
604 format ascii 1.0\r\n\
605 comment Hi, I'm your friendly comment.\r\n\
606 obj_info And I'm your object information.\r\n\
607 element point 2\r\n\
608 property int x\r\n\
609 property int y\r\n\
610 end_header\r\n\
611 -7 5\r\n\
612 2 4\r\n";
613 let mut bytes = txt.as_bytes();
614 let p = Parser::<DefaultElement>::new();
615 assert_ok!(p.read_ply(&mut bytes));
616 }
617 #[test]
618 fn read_property_ok() {
619 let p = Parser::<DefaultElement>::new();
620 let txt = "0 1 2 3";
621 let mut prop = KeyMap::<PropertyDef>::new();
622 prop.add(PropertyDef::new("a".to_string(), PropertyType::Scalar(ScalarType::Char)));
623 prop.add(PropertyDef::new("b".to_string(), PropertyType::Scalar(ScalarType::UChar)));
624 prop.add(PropertyDef::new("c".to_string(), PropertyType::Scalar(ScalarType::Short)));
625 prop.add(PropertyDef::new("d".to_string(), PropertyType::Scalar(ScalarType::UShort)));
626 let mut elem_def = ElementDef::new("dummy".to_string());
627 elem_def.properties = prop;
628
629 let properties = p.read_ascii_element(&txt, &elem_def);
630 assert!(properties.is_ok(), format!("error: {:?}", properties));
631 }
632 #[test]
633 fn magic_number_ok() {
634 assert_ok!(g::magic_number("ply"));
635 }
636 #[test]
637 fn magic_number_err() {
638 assert_err!(g::magic_number("py"));
639 assert_err!(g::magic_number("plyhi"));
640 assert_err!(g::magic_number("hiply"));
641 assert_err!(g::magic_number(" ply"));
642 assert_err!(g::magic_number("ply "));
643 }
644 #[test]
645 fn format_ok() {
646 assert_ok!(
647 g::format("format ascii 1.0"),
648 (Encoding::Ascii, Version{major: 1, minor: 0})
649 );
650 assert_ok!(
651 g::format("format binary_big_endian 2.1"),
652 (Encoding::BinaryBigEndian, Version{major: 2, minor: 1})
653 );
654 assert_ok!(
655 g::format("format binary_little_endian 1.0"),
656 (Encoding::BinaryLittleEndian, Version{major: 1, minor: 0})
657 );
658 }
659 #[test]
660 fn format_err() {
661 assert_err!(g::format("format asciii 1.0"));
662 assert_err!(g::format("format ascii -1.0"));
663 assert_err!(g::format("format ascii 1.0.3"));
664 assert_err!(g::format("format ascii 1."));
665 assert_err!(g::format("format ascii 1"));
666 assert_err!(g::format("format ascii 1.0a"));
667 }
668 #[test]
669 fn comment_ok() {
670 assert_ok!(g::comment("comment hi"), "hi");
671 assert_ok!(
672 g::comment("comment hi, I'm a comment!"),
673 "hi, I'm a comment!"
674 );
675 assert_ok!(g::comment("comment "), "");
676 assert_ok!(g::comment("comment\t"), "");
677 assert_ok!(g::comment("comment"), "");
678 assert_ok!(g::comment("comment\t"), "");
679 assert_ok!(g::comment("comment\thi"), "hi");
680 }
681 #[test]
682 fn comment_err() {
683 assert_err!(g::comment("commentt"));
684 assert_err!(g::comment("comment\n"));
685 assert_err!(g::comment("comment hi\na comment"));
686 assert_err!(g::comment("comment hi\r\na comment"));
687 assert_err!(g::comment("comment hi\ra comment"));
688 }
689 #[test]
690 fn obj_info_ok() {
691 assert_ok!(g::obj_info("obj_info Hi, I can help."), "Hi, I can help.");
692 assert_ok!(g::obj_info("obj_info"), "");
693 assert_ok!(g::obj_info("obj_info "), "");
694 assert_ok!(g::obj_info("obj_info\t"), "");
695 }
696 #[test]
697 fn obj_info_err() {
698 assert_err!(g::obj_info("obj_info\n"));
699 }
700 #[test]
701 fn element_ok() {
702 let mut e = ElementDef::new("vertex".to_string());
703 e.count = 8;
704 assert_ok!(
705 g::element("element vertex 8"),
706 e
707 );
708 }
709 #[test]
710 fn element_err() {
711 assert_err!(g::comment("element 8 vertex"));
712 }
713 #[test]
714 fn property_ok() {
715 assert_ok!(
716 g::property("property char c"),
717 PropertyDef::new("c".to_string(), PropertyType::Scalar(ScalarType::Char))
718 );
719 }
720 #[test]
721 fn property_list_ok() {
722 assert_ok!(
723 g::property("property list uchar int c"),
724 PropertyDef::new("c".to_string(), PropertyType::List(ScalarType::UChar, ScalarType::Int))
725 );
726 }
727 #[test]
728 fn line_ok() {
729 assert_ok!(g::line("ply "), Line::MagicNumber);
730 assert_ok!(g::line("format ascii 1.0 "), Line::Format((Encoding::Ascii, Version{major: 1, minor: 0})));
731 assert_ok!(g::line("comment a very nice comment "));
732 assert_ok!(g::line("element vertex 8 "));
733 assert_ok!(g::line("property float x "));
734 assert_ok!(g::line("element face 6 "));
735 assert_ok!(g::line("property list uchar int vertex_index "));
736 assert_ok!(g::line("end_header "));
737 }
738 #[test]
739 fn line_breaks_ok() {
740 assert_ok!(g::line("ply \n"), Line::MagicNumber); assert_ok!(g::line("ply \r"), Line::MagicNumber); assert_ok!(g::line("ply \r\n"), Line::MagicNumber); }
744 #[test]
745 fn data_line_ok() {
746 assert_ok!(
747 g::data_line("+7 -7 7 +5.21 -5.21 5.21 +0 -0 0 \r\n"),
748 vec!["+7", "-7", "7", "+5.21", "-5.21", "5.21", "+0", "-0", "0"]
749 );
750 assert_ok!(
751 g::data_line("034 8e3 8e-3"),
752 vec!["034", "8e3", "8e-3"]
753 );
754 assert_ok!(g::data_line(""), Vec::<String>::new());
755 }
756 #[test]
757 fn data_line_err() {
758 assert_err!(g::data_line("++3"));
759 assert_err!(g::data_line("+-3"));
760 assert_err!(g::data_line("five"));
761 }
762}