trans_gen/
lib.rs

1pub use trans;
2
3use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, HashSet};
5use std::fmt::Write;
6use std::path::Path;
7use trans::*;
8
9pub mod gens;
10
11#[derive(Debug)]
12pub struct File {
13    pub path: String,
14    pub content: String,
15}
16
17#[derive(Debug)]
18pub struct GenResult {
19    pub files: Vec<File>,
20}
21
22impl GenResult {
23    pub fn write_to<P: AsRef<Path>>(&self, target_dir: P) -> std::io::Result<()> {
24        let target_dir = target_dir.as_ref();
25        for file in &self.files {
26            if let Some(parent) = Path::new(&file.path).parent() {
27                std::fs::create_dir_all(target_dir.join(parent))?;
28            }
29            use std::io::Write;
30            std::fs::File::create(target_dir.join(&file.path))?
31                .write_all(file.content.as_bytes())?;
32        }
33        Ok(())
34    }
35}
36
37impl From<HashMap<String, String>> for GenResult {
38    fn from(file_map: HashMap<String, String>) -> Self {
39        Self {
40            files: file_map
41                .into_iter()
42                .map(|(path, content)| File { path, content })
43                .collect(),
44        }
45    }
46}
47
48impl From<Vec<File>> for GenResult {
49    fn from(files: Vec<File>) -> Self {
50        Self { files }
51    }
52}
53
54pub trait Generator {
55    type Options: Default;
56    fn new(name: &str, version: &str, options: Self::Options) -> Self;
57    fn add_only(&mut self, schema: &trans::Schema);
58    fn result(self) -> GenResult;
59}
60
61pub struct GeneratorImpl<T: Generator> {
62    inner: T,
63    added: HashMap<trans::Name, trans::Schema>,
64}
65
66impl<T: Generator> GeneratorImpl<T> {
67    pub fn new(name: &str, version: &str, options: T::Options) -> Self {
68        Self {
69            inner: T::new(name, version, options),
70            added: HashMap::new(),
71        }
72    }
73    pub fn add(&mut self, schema: &Schema) {
74        let schema_name = schema.full_name();
75        let current = self.added.get(&schema_name);
76        if let Some(current) = current {
77            assert_eq!(
78                current, schema,
79                "Two schemas with same name but different structure"
80            );
81            return;
82        }
83        self.added.insert(schema_name, schema.clone());
84        match schema {
85            Schema::Struct(Struct { fields, .. }) => {
86                for field in fields {
87                    self.add(&field.schema);
88                }
89            }
90            Schema::OneOf { variants, .. } => {
91                for variant in variants {
92                    for field in &variant.fields {
93                        self.add(&field.schema);
94                    }
95                }
96            }
97            Schema::Option(inner) => {
98                self.add(inner);
99            }
100            Schema::Vec(inner) => {
101                self.add(inner);
102            }
103            Schema::Map(key_type, value_type) => {
104                self.add(key_type);
105                self.add(value_type);
106            }
107            Schema::Bool
108            | Schema::Int32
109            | Schema::Int64
110            | Schema::Float32
111            | Schema::Float64
112            | Schema::String
113            | Schema::Enum { .. } => {}
114        }
115        self.inner.add_only(schema);
116    }
117    pub fn result(self) -> GenResult {
118        self.inner.result()
119    }
120}
121
122pub struct Writer {
123    content: String,
124    ident_level: usize,
125}
126
127impl Writer {
128    pub fn new() -> Self {
129        Self {
130            content: String::new(),
131            ident_level: 0,
132        }
133    }
134    pub fn inc_ident(&mut self) {
135        self.ident_level += 1;
136    }
137    pub fn dec_ident(&mut self) {
138        self.ident_level -= 1;
139    }
140    pub fn get(self) -> String {
141        assert_eq!(self.ident_level, 0, "Incorrect indentation");
142        self.content
143    }
144}
145
146impl std::fmt::Write for Writer {
147    fn write_str(&mut self, s: &str) -> std::fmt::Result {
148        for c in s.chars() {
149            if c != '\n' && self.content.chars().last().unwrap_or('\n') == '\n' {
150                for _ in 0..self.ident_level * 4 {
151                    self.content.push(' ');
152                }
153            }
154            self.content.push(c);
155        }
156        Ok(())
157    }
158}