seam/
lib.rs

1#![allow(incomplete_features)]
2#![feature(pattern)]
3#![feature(box_patterns)]
4#![feature(associated_type_defaults)]
5
6pub mod parse;
7pub mod assemble;
8
9use parse::{expander, parser, lexer};
10
11use std::{fs, io, path::Path};
12
13const fn parse_u8(s: &str) -> u8 {
14    match u8::from_str_radix(s, 10) {
15        Ok(n) => n,
16        Err(_) => panic!("is not a base 10 integer"),
17    }
18}
19
20pub const VERSION: (u8, u8, u8) = (
21    parse_u8(env!("CARGO_PKG_VERSION_MAJOR")),
22    parse_u8(env!("CARGO_PKG_VERSION_MINOR")),
23    parse_u8(env!("CARGO_PKG_VERSION_PATCH")),
24);
25
26/* Utilities. */
27
28/// See: <https://stackoverflow.com/a/30353928>
29pub trait CloneBox {
30    fn clone_box(&self) -> *mut ();
31}
32
33impl<'a, T> CloneBox for T where T: Clone + 'a {
34    fn clone_box(&self) -> *mut () {
35        Box::<T>::into_raw(Box::new(self.clone())) as *mut ()
36    }
37}
38
39#[macro_export]
40macro_rules! impl_clone_box {
41    ($($lif:tt),* ; $tra:ty) => {
42        impl< $($lif),* > Clone for Box< $tra > {
43            fn clone(&self) -> Box< $tra > {
44                unsafe {
45                    *Box::from_raw(self.clone_box() as *mut Self)
46                }
47            }
48        }
49    };
50    ($($lif:tt),* ; $($gen:tt),* ; $tra:ty) => {
51        impl< $($lif),* , $($gen),* > Clone for Box< $tra > {
52            fn clone(&self) -> Box< $tra > {
53                unsafe {
54                    *Box::from_raw(self.clone_box() as *mut Self)
55                }
56            }
57        }
58    };
59}
60
61/* Library helpers. */
62
63pub fn tree_builder<'a, P: AsRef<Path>>(source_path: Option<P>, string: String)
64    -> expander::Expander<'a> {
65    let path = source_path.map_or("<stdin>".to_string(),
66        |s| s.as_ref().to_string_lossy().to_string());
67    let tokenizer = lexer::Lexer::new(path, string);
68    let builder = parser::Parser::new(tokenizer);
69    expander::Expander::new(builder)
70}
71
72pub fn tree_builder_file<'a>(path: &Path)
73    -> io::Result<expander::Expander<'a>> {
74    let contents = fs::read_to_string(&path)?;
75    Ok(tree_builder(Some(path), contents))
76}
77
78pub fn tree_builder_stream(stream: &mut impl io::Read)
79    -> io::Result<expander::Expander> {
80    let mut contents = String::new();
81    stream.read_to_string(&mut contents)?;
82    Ok(tree_builder(Option::<&Path>::None, contents))
83}
84
85#[cfg(test)]
86#[path = "./tests.rs"]
87mod tests;