1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use crate::error::Error;
use crate::file_writer;
use std::fs::File;
use std::path::Path;

pub mod ascii7;
pub mod backward_compatible;
pub mod bidi_class;
pub mod codepoints;
pub mod derived_property;
pub mod exceptions;
pub mod ucd_generator;
pub mod unicode_version;

/// This is the main code generator element. It aggregates other
/// [`CodeGen`] elements. The resulting file will contain the
/// code generated by every element added to the code generator.
pub struct RustCodeGen {
    file: File,
    generators: Vec<Box<dyn CodeGen>>,
}

impl RustCodeGen {
    /// Creates a new Rust code generator
    /// # Arguments:
    /// * `filename` - The file name
    /// # Returns:
    /// This method returns a new [`RustCodeGen`] instance if no errors
    /// occurs when the file is created
    pub fn new<P>(filename: P) -> Result<Self, Error>
    where
        P: AsRef<Path>,
    {
        Ok(Self {
            file: File::create(filename)?,
            generators: Vec::new(),
        })
    }

    /// Adds an element to the code generator. Each element must implement
    /// [`CodeGen`] trait.
    /// # Arguments:
    /// * `gen` - The code generator element
    pub fn add(&mut self, gen: Box<dyn CodeGen>) {
        self.generators.push(gen);
    }

    /// Write the code into the file created on construction. In case of
    /// error, the file generated could stay in an incomplete or
    /// inconsistent state.
    pub fn generate_code(&mut self) -> Result<(), Error> {
        file_writer::generate_file_header(&mut self.file)?;
        let it = self.generators.iter_mut();
        for gen in it {
            gen.generate_code(&mut self.file)?;
        }
        Ok(())
    }
}

/// Trait implemented by all elements which are able to generate code.
pub trait CodeGen {
    /// Writes the Rust code itself.
    /// # Arguments:
    /// * `file` - The output file
    fn generate_code(&mut self, file: &mut File) -> Result<(), Error>;
}