1#![deny(unsafe_code)]
97#![warn(
98 missing_docs,
99 missing_debug_implementations,
100 missing_copy_implementations,
101 trivial_casts,
102 trivial_numeric_casts,
103 unused_import_braces,
104 unused_qualifications
105)]
106
107#[macro_use]
108mod macros;
109mod api;
110mod core;
111mod fx;
112mod physics;
113mod url;
114
115use std::convert::{TryFrom, TryInto};
116use std::fmt::{Debug, Display};
117use std::io::{BufRead, BufReader, Write};
118use std::ops::Deref;
119use std::path::Path;
120use std::str::FromStr;
121
122pub use crate::{api::*, core::*, fx::*, physics::*};
123use minidom::quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event};
124pub use minidom::Element;
125pub use url::Url;
126
127type XReader<R> = minidom::quick_xml::Reader<R>;
128type XWriter<R> = minidom::quick_xml::Writer<R>;
129
130#[derive(Debug)]
132pub enum Error {
133 Minidom(minidom::Error),
135 Other(&'static str),
137 Str(String),
139}
140
141impl From<std::io::Error> for Error {
142 fn from(v: std::io::Error) -> Self {
143 Self::Minidom(v.into())
144 }
145}
146
147impl From<minidom::Error> for Error {
148 fn from(v: minidom::Error) -> Self {
149 Self::Minidom(v)
150 }
151}
152
153impl From<minidom::quick_xml::Error> for Error {
154 fn from(v: minidom::quick_xml::Error) -> Self {
155 Self::Minidom(v.into())
156 }
157}
158
159impl From<&'static str> for Error {
160 fn from(v: &'static str) -> Self {
161 Self::Other(v)
162 }
163}
164
165impl From<String> for Error {
166 fn from(v: String) -> Self {
167 Self::Str(v)
168 }
169}
170
171type Result<T, E = Error> = std::result::Result<T, E>;
172
173type ElementIter<'a> = std::iter::Peekable<minidom::Children<'a>>;
174
175fn get_text(element: &Element) -> Option<&str> {
176 let mut it = element.nodes();
177 let text = match it.next() {
178 None => "",
179 Some(s) => s.as_text()?,
180 };
181 if it.next().is_some() {
182 return None;
183 }
184 Some(text)
185}
186
187fn parse_text(element: &Element) -> Result<String> {
188 Ok(get_text(element).ok_or("expecting a text node")?.to_owned())
189}
190
191fn parse_array<T: FromStr>(e: &Element) -> Result<Box<[T]>> {
192 get_text(e)
193 .ok_or("expected text node")?
194 .split_ascii_whitespace()
195 .map(|s| s.parse())
196 .collect::<Result<_, _>>()
197 .map_err(|_| "parse error".into())
198}
199
200fn parse_array_n<T: FromStr, const N: usize>(element: &Element) -> Result<Box<[T; N]>> {
201 Ok(parse_array(element)?
202 .try_into()
203 .map_err(|_| "unexpected number of elements")?)
204}
205
206fn parse_elem<T: FromStr>(e: &Element) -> Result<T> {
207 get_text(e)
208 .ok_or("expected text node")?
209 .parse()
210 .map_err(|_| "parse error".into())
211}
212
213fn parse_attr<T: FromStr>(attr: Option<&str>) -> Result<Option<T>> {
214 Ok(match attr {
215 None => None,
216 Some(s) => Some(s.parse().map_err(|_| "parse failure")?),
217 })
218}
219
220fn parse_one<'a, T>(
221 name: &str,
222 it: &mut impl Iterator<Item = &'a Element>,
223 f: impl FnOnce(&'a Element) -> Result<T>,
224) -> Result<T> {
225 let e = it.next().ok_or_else(|| format!("expected <{}>", name))?;
226 if e.name() != name {
227 return Err(format!("expected <{}>", name).into());
228 }
229 f(e)
230}
231
232fn parse_one_many<'a, T>(
233 it: &mut impl Iterator<Item = &'a Element>,
234 f: impl FnOnce(&'a Element) -> Result<Option<T>>,
235) -> Result<T> {
236 let e = it.next().ok_or("expected element")?;
237 Ok(f(e)?.ok_or("expected element")?)
238}
239
240fn parse_opt<'a, T>(
241 name: &str,
242 it: &mut ElementIter<'a>,
243 f: impl FnOnce(&'a Element) -> Result<T>,
244) -> Result<Option<T>> {
245 let mut res = None;
246 if let Some(&e) = it.peek() {
247 if e.name() == name {
248 res = Some(f(e)?);
249 it.next();
250 }
251 }
252 Ok(res)
253}
254
255fn parse_opt_many<'a, T>(
256 it: &mut ElementIter<'a>,
257 f: impl FnOnce(&'a Element) -> Result<Option<T>>,
258) -> Result<Option<T>> {
259 let res = match it.peek() {
260 None => None,
261 Some(&e) => f(e)?,
262 };
263 if res.is_some() {
264 it.next();
265 }
266 Ok(res)
267}
268
269fn parse_list<'a, T>(
270 name: &str,
271 it: &mut ElementIter<'a>,
272 mut f: impl FnMut(&'a Element) -> Result<T>,
273) -> Result<Vec<T>> {
274 parse_list_many(it, |e| {
275 Ok(if e.name() == name { Some(f(e)?) } else { None })
276 })
277}
278
279fn finish<'a, T>(t: T, mut it: impl Iterator<Item = &'a Element>) -> Result<T> {
280 if let Some(e) = it.next() {
281 return Err(format!("unexpected node <{}>", e.name()).into());
282 }
283 Ok(t)
284}
285
286fn parse_list_many<'a, T>(
287 it: &mut ElementIter<'a>,
288 mut f: impl FnMut(&'a Element) -> Result<Option<T>>,
289) -> Result<Vec<T>> {
290 let mut res = vec![];
291 while let Some(&e) = it.peek() {
292 match f(e)? {
293 Some(t) => res.push(t),
294 None => break,
295 }
296 it.next();
297 }
298 Ok(res)
299}
300
301fn print_str(s: &str, w: &mut XWriter<impl Write>) -> Result<()> {
302 Ok(w.write_event(Event::Text(BytesText::new(s)))?)
303}
304
305fn print_elem<T: Display>(elem: &T, w: &mut XWriter<impl Write>) -> Result<()> {
306 print_str(&format!("{}", elem), w)
307}
308
309#[inline]
310fn opt<'a, T, E>(elem: &'a Option<T>, f: impl FnOnce(&'a T) -> Result<(), E>) -> Result<(), E> {
311 if let Some(elem) = elem {
312 f(elem)?
313 }
314 Ok(())
315}
316
317#[inline]
318fn many<'a, T, E>(elem: &'a [T], f: impl FnMut(&'a T) -> Result<(), E>) -> Result<(), E> {
319 elem.iter().try_for_each(f)
320}
321
322fn arr_to_string<T: Display>(elem: &[T]) -> Option<String> {
323 let (e1, rest) = elem.split_first()?;
324 let mut s = format!("{}", e1);
325 for e in rest {
326 use std::fmt::Write;
327 write!(s, " {}", e).expect("can't fail")
328 }
329 Some(s)
330}
331fn print_arr<T: Display>(elem: &[T], w: &mut XWriter<impl Write>) -> Result<()> {
332 opt(&arr_to_string(elem), |s| print_str(s, w))
333}
334
335#[doc(hidden)]
336#[derive(Debug)]
337pub struct ElemBuilder<'a>(BytesStart<'a>);
338
339struct ElemEnd<'a>(BytesEnd<'a>);
340
341impl<'a> ElemBuilder<'a> {
342 #[inline]
343 fn new(name: &'a str) -> Self {
344 Self(BytesStart::new(name))
345 }
346
347 fn print_str(name: &'a str, elem: &str, w: &mut XWriter<impl Write>) -> Result<()> {
348 let e = Self::new(name).start(w)?;
349 print_str(elem, w)?;
350 e.end(w)
351 }
352
353 fn print<T: Display>(name: &'a str, elem: &T, w: &mut XWriter<impl Write>) -> Result<()> {
354 let e = Self::new(name).start(w)?;
355 print_elem(elem, w)?;
356 e.end(w)
357 }
358
359 fn opt_print<T: Display>(
360 name: &'a str,
361 elem: &Option<T>,
362 w: &mut XWriter<impl Write>,
363 ) -> Result<()> {
364 opt(elem, |e| Self::print(name, e, w))
365 }
366
367 fn def_print<T: Display + PartialEq>(
368 name: &'a str,
369 value: T,
370 def: T,
371 w: &mut XWriter<impl Write>,
372 ) -> Result<()> {
373 if value != def {
374 Self::print(name, &value, w)?
375 }
376 Ok(())
377 }
378
379 fn print_arr<T: Display>(name: &'a str, elem: &[T], w: &mut XWriter<impl Write>) -> Result<()> {
380 let e = Self::new(name).start(w)?;
381 print_arr(elem, w)?;
382 e.end(w)
383 }
384
385 #[inline]
386 fn raw_attr(&mut self, key: &str, value: &[u8]) {
387 self.0.push_attribute((key.as_bytes(), value));
388 }
389
390 #[inline]
391 fn attr(&mut self, key: &str, value: &str) {
392 self.0.push_attribute((key, value));
393 }
394
395 fn opt_attr(&mut self, key: &str, value: &Option<String>) {
396 if let Some(value) = value {
397 self.attr(key, value)
398 }
399 }
400
401 #[inline]
402 fn print_attr(&mut self, key: &str, value: impl Display) {
403 self.0.push_attribute((key, &*format!("{}", value)));
404 }
405
406 fn opt_print_attr(&mut self, key: &str, value: &Option<impl Display>) {
407 if let Some(value) = value {
408 self.0.push_attribute((key, &*format!("{}", value)));
409 }
410 }
411
412 fn def_print_attr<T: Display + PartialEq>(&mut self, key: &str, value: T, def: T) {
413 if value != def {
414 self.print_attr(key, value)
415 }
416 }
417
418 fn start(self, w: &mut XWriter<impl Write>) -> Result<ElemEnd<'static>> {
419 let end = self.0.to_end().into_owned();
420 w.write_event(Event::Start(self.0))?;
421 Ok(ElemEnd(end))
422 }
423
424 fn end(self, w: &mut XWriter<impl Write>) -> Result<()> {
425 Ok(w.write_event(Event::Empty(self.0))?)
426 }
427}
428
429impl<'a> ElemEnd<'a> {
430 fn end(self, w: &mut XWriter<impl Write>) -> Result<()> {
431 Ok(w.write_event(Event::End(self.0))?)
432 }
433}
434
435use private::{XNode, XNodeWrite};
436pub(crate) mod private {
437 use super::*;
438
439 pub trait XNode: XNodeWrite + Sized {
441 const NAME: &'static str;
443
444 fn parse(element: &Element) -> Result<Self>;
447
448 fn parse_box(element: &Element) -> Result<Box<Self>> {
451 Self::parse(element).map(Box::new)
452 }
453
454 fn parse_one<'a>(it: &mut impl Iterator<Item = &'a Element>) -> Result<Self> {
456 parse_one(Self::NAME, it, Self::parse)
457 }
458
459 fn parse_opt(it: &mut ElementIter<'_>) -> Result<Option<Self>> {
462 parse_opt(Self::NAME, it, Self::parse)
463 }
464
465 fn parse_opt_box(it: &mut ElementIter<'_>) -> Result<Option<Box<Self>>> {
468 parse_opt(Self::NAME, it, Self::parse_box)
469 }
470
471 fn parse_list(it: &mut ElementIter<'_>) -> Result<Vec<Self>> {
474 parse_list(Self::NAME, it, Self::parse)
475 }
476
477 fn parse_list_n<const N: usize>(it: &mut ElementIter<'_>) -> Result<Vec<Self>> {
481 let arr = parse_list(Self::NAME, it, Self::parse)?;
482 if arr.len() < N {
483 return Err(format!("parse error: expected {} {} elements", N, Self::NAME).into());
484 }
485 Ok(arr)
486 }
487
488 #[doc(hidden)]
490 fn elem<'a>() -> ElemBuilder<'a> {
491 ElemBuilder::new(Self::NAME)
492 }
493 }
494
495 pub trait XNodeWrite {
496 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()>;
498 }
499}
500
501impl<T: XNodeWrite> XNodeWrite for Box<T> {
502 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
503 (**self).write_to(w)
504 }
505}
506
507impl<T: XNodeWrite> XNodeWrite for Option<T> {
508 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
509 opt(self, |e| e.write_to(w))
510 }
511}
512
513impl<T: XNodeWrite> XNodeWrite for Vec<T> {
514 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
515 many(self, |e| e.write_to(w))
516 }
517}
518
519impl XNodeWrite for Element {
520 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
521 use std::{cell::RefCell, collections::BTreeMap};
522 thread_local! {
523 static COLLADA_PREFIX: RefCell<BTreeMap<Option<String>, String>> =
524 const { RefCell::new(BTreeMap::new()) };
525 }
526 COLLADA_PREFIX.with(|pfxs| {
527 let mut pfxs = pfxs.borrow_mut();
528 if pfxs.is_empty() {
529 pfxs.insert(None, "http://www.collada.org/2005/11/COLLADASchema".into());
530 }
531 Ok(self.write_to_inner(w, &mut pfxs)?)
532 })
533 }
534}
535
536impl XNodeWrite for () {
537 fn write_to<W: Write>(&self, _: &mut XWriter<W>) -> Result<()> {
538 Ok(())
539 }
540}
541
542#[derive(Clone, Debug)]
546pub struct Document {
547 pub asset: Asset,
549 pub library: Vec<LibraryElement>,
551 pub scene: Option<Scene>,
554 pub extra: Vec<Extra>,
556}
557
558impl FromStr for Document {
559 type Err = Error;
560 fn from_str(s: &str) -> Result<Self> {
561 Self::try_from(s.as_bytes())
562 }
563}
564
565impl TryFrom<&str> for Document {
566 type Error = Error;
567 fn try_from(s: &str) -> Result<Self> {
568 Self::from_str(s)
569 }
570}
571
572impl TryFrom<&[u8]> for Document {
573 type Error = Error;
574 fn try_from(s: &[u8]) -> Result<Self> {
575 Self::from_reader(std::io::Cursor::new(s))
576 }
577}
578
579impl Document {
580 pub fn new(asset: Asset) -> Self {
582 Self {
583 asset,
584 library: vec![],
585 scene: None,
586 extra: vec![],
587 }
588 }
589
590 pub fn create_now() -> Self {
592 Self::new(Asset::create_now())
593 }
594
595 pub fn push_library<T: ParseLibrary>(&mut self, items: Vec<T>) {
597 self.library.push(T::mk_element(Library::new(items)))
598 }
599
600 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
602 Self::from_reader(BufReader::new(std::fs::File::open(path)?))
603 }
604
605 pub fn from_reader<R: BufRead>(reader: R) -> Result<Self> {
609 Self::from_xml_reader(&mut XReader::from_reader(reader))
610 }
611
612 pub fn from_xml_reader<R: BufRead>(reader: &mut XReader<R>) -> Result<Self> {
615 let root = Element::from_reader(reader)?;
616 Self::parse(&root)
617 }
618
619 pub fn write_to<W: Write>(&self, w: W) -> Result<()> {
621 XNodeWrite::write_to(self, &mut XWriter::new_with_indent(w, b' ', 2))
622 }
623}
624
625impl XNode for Document {
626 const NAME: &'static str = "COLLADA";
627 fn parse(element: &Element) -> Result<Self> {
629 if element.name() != Self::NAME {
630 return Err("Expected COLLADA root node".into());
631 }
632 if element.attr("version") != Some("1.4.1") {
633 return Err("Unsupported COLLADA version".into());
634 }
635 let mut it = element.children().peekable();
636 Ok(Document {
637 asset: Asset::parse_one(&mut it)?,
638 library: parse_list_many(&mut it, LibraryElement::parse)?,
639 scene: Scene::parse_opt(&mut it)?,
640 extra: Extra::parse_many(it)?,
641 })
642 }
643}
644
645impl XNodeWrite for Document {
646 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
647 w.write_event(Event::Decl(BytesDecl::new("1.0", Some("utf-8"), None)))?;
648 let mut e = Self::elem();
649 e.raw_attr("xmlns", b"http://www.collada.org/2005/11/COLLADASchema");
650 e.raw_attr("version", b"1.4.1");
651 e.raw_attr("xmlns:xsi", b"http://www.w3.org/2001/XMLSchema-instance");
652 let e = e.start(w)?;
653 self.asset.write_to(w)?;
654 self.library.write_to(w)?;
655 self.scene.write_to(w)?;
656 self.extra.write_to(w)?;
657 e.end(w)
658 }
659}
660
661impl CollectLocalMaps for Document {
662 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
663 self.library.collect_local_maps(maps);
664 }
665}