1#![warn(
29 unreachable_pub,
30 missing_debug_implementations,
31 missing_copy_implementations,
32 elided_lifetimes_in_paths,
33 missing_docs
34)]
35#![allow(
37 clippy::match_same_arms,
38 clippy::needless_doctest_main,
39 clippy::map_unwrap_or,
40 clippy::redundant_field_names,
41 clippy::type_complexity
42)]
43#![warn(
44 clippy::unwrap_used,
45 clippy::mut_mut,
47 clippy::non_ascii_literal,
48 clippy::similar_names,
49 clippy::unicode_not_nfc,
50 clippy::enum_glob_use,
51 clippy::if_not_else,
52 clippy::items_after_statements,
53 clippy::used_underscore_binding
54)]
55#![deny(unsafe_code)]
56
57use std::fs::File;
58use std::io::Write;
59use std::path::{Path, PathBuf};
60
61use convert_case::{Case, Casing};
62use ovsdb::schema::Schema;
63use quote::format_ident;
64
65mod attributes;
66mod entity;
67mod enumeration;
68mod field;
69use attributes::Attributes;
70use entity::Entity;
71use enumeration::Enumeration;
72use field::{Field, Kind};
73
74#[derive(thiserror::Error, Debug)]
76pub enum Error {
77 #[error("Unexpected IO Error")]
79 Io(#[from] std::io::Error),
80 #[error("Token parse error")]
82 Tokens(#[from] syn::Error),
83 #[error("Parsing error")]
85 OVSDB(#[from] ovsdb::Error),
86}
87
88pub type Result<T> = std::result::Result<T, Error>;
90
91pub(crate) fn str_to_name<T>(str: T) -> String
92where
93 T: AsRef<str>,
94{
95 str.as_ref().to_case(Case::UpperCamel)
96}
97
98pub(crate) fn name_to_ident<T>(name: T) -> syn::Ident
99where
100 T: AsRef<str>,
101{
102 format_ident!("{}", name.as_ref())
103}
104
105#[derive(Clone, Debug, Default)]
107pub struct Builder {
108 out_dir: Option<PathBuf>,
109}
110
111impl Builder {
112 fn new() -> Self {
113 Self::default()
114 }
115
116 fn generate_modules(&self, schema: &Schema, directory: &Path) -> Result<()> {
117 std::fs::create_dir_all(directory)?;
118
119 let mod_filename = directory.join("mod.rs");
120 let mut mod_file = File::create(mod_filename)?;
121 for table in schema.tables() {
122 let filename = directory.join(format!("{}.rs", table.name().to_case(Case::Snake)));
123 let entity = Entity::from_table(table);
124 entity.to_file(&filename)?;
125
126 mod_file.write_all(
127 format!(
128 "mod {table_name};\npub use {table_name}::*;\n",
129 table_name = &table.name().to_case(Case::Snake)
130 )
131 .as_bytes(),
132 )?;
133 }
134 Ok(())
135 }
136
137 pub fn compile<P>(self, schema_file: P, module: P) -> Result<()>
139 where
140 P: AsRef<Path>,
141 {
142 let mut output_dir = match &self.out_dir {
143 Some(dir) => dir.to_path_buf(),
144 None => match std::env::var("OUT_DIR") {
145 Ok(val) => PathBuf::from(val),
146 Err(_) => todo!(),
147 },
148 };
149
150 let schema = ovsdb::schema::Schema::from_file(schema_file)?;
151
152 output_dir.push(module);
153
154 self.generate_modules(&schema, &output_dir)
155 }
156}
157
158pub fn configure() -> Builder {
160 Builder::new()
161}