c_emit/
lib.rs

1//! # **The C Code Generator for Rust.**
2//!
3//! C-Emit provides a polished Builder API for generating C Code.
4//!
5//! ## Example
6//!
7//! ```rust
8//! use c_emit::{Code, CArg};
9//!
10//! let mut code = Code::new();
11//!
12//! code.include("stdio.h");
13//! code.call_func_with_args("printf", vec![CArg::String("Hello, world!")]);
14//! assert_eq!(code.to_string(), r#"
15//! #include<stdio.h>
16//! int main() {
17//! printf("Hello, world!");
18//! return 0;
19//! }
20//! "#.trim_start().to_string());
21//! ```
22
23#![deny(missing_docs)]
24
25use std::fmt::{Display, Formatter};
26
27/// # The Code Struct.
28///
29/// ## Example
30///
31/// ```rust
32/// use c_emit::Code;
33///
34/// let mut code = Code::new();
35///
36/// code.exit(1);
37///
38/// assert_eq!(code.to_string(), r#"
39/// int main() {
40/// return 1;
41/// }
42/// "#.trim_start().to_string());
43/// ```
44pub struct Code<'a> {
45    code: String,
46    requires: Vec<&'a str>,
47    exit: i32,
48}
49
50/// # The C Argument.
51#[derive(Debug, Clone, Copy)]
52pub enum CArg<'a> {
53    /// The String argument.
54    String(&'a str),
55
56    /// The identifier argument.
57    Ident(&'a str),
58
59    /// The i32 argument.
60    Int32(i32),
61
62    /// The i64 argument.
63    Int64(i64),
64
65    /// The float argument.
66    Float(f32),
67
68    /// The 'double' argument.
69    Double(f64),
70
71    /// The boolean argument.
72    Bool(bool),
73
74    /// The character argument.
75    Char(char),
76}
77
78/// # The variable types.
79#[derive(Debug, Clone, Copy)]
80pub enum VarTypes {
81    /// String.
82    String,
83
84    /// i32.
85    Int32,
86
87    /// i64.
88    Int64,
89
90    /// Float.
91    Float,
92
93    /// 'Double'.
94    Double,
95
96    /// Boolean.
97    Bool,
98
99    /// Character.
100    Char,
101}
102
103/// # The variable initialization.
104#[derive(Debug, Clone, Copy)]
105pub enum VarInit<'a> {
106    /// Initialize a string.
107    String(&'a str),
108
109    /// Initialize a variable with an identifier.
110    Ident(VarTypes, &'a str),
111
112    /// Initialize an i32.
113    Int32(i32),
114
115    /// Initialize an i64.
116    Int64(i64),
117
118    /// Initialize a float.
119    Float(f32),
120
121    /// Initialize a 'double'.
122    Double(f64),
123
124    /// Initialize a boolean.
125    Bool(bool),
126
127    /// Initialize a character.
128    Char(char),
129
130    /// **(FOR STRINGS ONLY!)** Set the variable to uninitialized with a specific size.
131    SizeString(usize),
132}
133
134impl Default for Code<'_> {
135    fn default() -> Self {
136        Self::new()
137    }
138}
139
140impl Code<'_> {
141    /// # Create a new C Code object.
142    ///
143    /// ## Example
144    /// ```rust
145    /// use c_emit::Code;
146    ///
147    /// let code = Code::new();
148    ///
149    /// assert_eq!(code.to_string(), r#"
150    /// int main() {
151    /// return 0;
152    /// }
153    /// "#.trim_start().to_string());
154    /// ```
155    pub fn new() -> Self {
156        Self {
157            code: String::new(),
158            requires: vec![],
159            exit: 0,
160        }
161    }
162
163    /// # Add the exit code to the main function.
164    ///
165    /// ## Example
166    ///
167    /// ```rust
168    /// use c_emit::Code;
169    ///
170    /// let mut code = Code::new();
171    ///
172    /// code.exit(1);
173    ///
174    /// assert_eq!(code.to_string(), r#"
175    /// int main() {
176    /// return 1;
177    /// }
178    /// "#.trim_start().to_string());
179    /// ```
180    pub fn exit(&mut self, code: i32) {
181        self.exit = code;
182    }
183
184    /// # #include < any file into the C Code. >
185    ///
186    /// ## Example
187    ///
188    /// ```rust
189    /// use c_emit::Code;
190    ///
191    /// let mut code = Code::new();
192    ///
193    /// code.include("stdio.h");
194    ///
195    /// assert_eq!(code.to_string(), r#"
196    /// #include<stdio.h>
197    /// int main() {
198    /// return 0;
199    /// }
200    /// "#.trim_start().to_string());
201    /// ```
202    pub fn include(&mut self, file: &'static str) {
203        if self.requires.contains(&file) {
204            return;
205        }
206        self.requires.push(file);
207    }
208
209    /// # Call a function WITHOUT arguments.
210    ///
211    /// ## Example
212    ///
213    /// ```rust
214    /// use c_emit::Code;
215    ///
216    /// let mut code = Code::new();
217    ///
218    /// code.call_func("printf");
219    ///
220    /// assert_eq!(code.to_string(), r#"
221    /// int main() {
222    /// printf();
223    /// return 0;
224    /// }
225    /// "#.trim_start().to_string());
226    /// ```
227    pub fn call_func(&mut self, func: &str) {
228        self.code.push_str(func);
229        self.code.push_str("();\n")
230    }
231
232    /// # Call a function WITH arguments.
233    ///
234    /// ## Example
235    ///
236    /// ```rust
237    /// use c_emit::{Code, CArg};
238    ///
239    /// let mut code = Code::new();
240    ///
241    /// code.call_func_with_args("printf", vec![CArg::String("Hello, world!")]);
242    ///
243    /// assert_eq!(code.to_string(), r#"
244    /// int main() {
245    /// printf("Hello, world!");
246    /// return 0;
247    /// }
248    /// "#.trim_start().to_string());
249    /// ```
250    pub fn call_func_with_args(&mut self, func: &str, args: Vec<CArg>) {
251        self.code.push_str(func);
252        self.code.push('(');
253
254        for arg in args {
255            match arg {
256                CArg::String(s) => {
257                    let s = s.replace("\r\n", "\\r\\n");
258                    let s = s.replace('\n', "\\n");
259                    let s = s.replace('\t', "\\t");
260                    let s = s.replace('"', "\\\"");
261
262                    self.code.push('"');
263                    self.code.push_str(s.as_str());
264                    self.code.push('"');
265                }
266                CArg::Ident(id) => {
267                    self.code.push_str(id);
268                }
269                CArg::Int32(n) => {
270                    self.code.push_str(&n.to_string());
271                }
272                CArg::Int64(n) => {
273                    self.code.push_str(&n.to_string());
274                }
275                CArg::Float(n) => {
276                    self.code.push_str(&n.to_string());
277                }
278                CArg::Double(n) => {
279                    self.code.push_str(&n.to_string());
280                }
281                CArg::Bool(b) => {
282                    self.code.push_str(&b.to_string());
283                }
284                CArg::Char(c) => {
285                    self.code.push(c);
286                }
287            }
288            self.code.push(',');
289        }
290
291        if self.code.ends_with(',') {
292            self.code = self.code.strip_suffix(',').unwrap().to_string();
293        }
294
295        self.code.push_str(");\n")
296    }
297
298    /// # Make a new variable.
299    ///
300    /// ## Example
301    ///
302    /// ```rust
303    /// use c_emit::{Code, CArg, VarInit};
304    ///
305    /// let mut code = Code::new();
306    ///
307    /// code.new_var("a", VarInit::String("hello"));
308    ///
309    /// assert_eq!(code.to_string(), r#"
310    /// int main() {
311    /// char a[]="hello";
312    /// return 0;
313    /// }
314    /// "#.trim_start().to_string());
315    ///
316    /// ```
317    /// ## NOTE:
318    /// Set the `initval` argument to `None` to make the variable uninitialized.
319    pub fn new_var<S: AsRef<str>>(&mut self, name: S, value: VarInit) {
320        let name = name.as_ref();
321
322        match value {
323            VarInit::String(s) => {
324                self.code.push_str("char ");
325                self.code.push_str(name);
326
327                self.code.push_str("[]=\"");
328                self.code.push_str(s);
329                self.code.push_str("\";");
330                self.code.push('\n');
331            }
332            VarInit::Ident(ty, ident) => {
333                self.code.push_str(match ty {
334                    VarTypes::String => "char ",
335                    VarTypes::Int32 => "int ",
336                    VarTypes::Int64 => "int ",
337                    VarTypes::Float => "float ",
338                    VarTypes::Double => "double ",
339                    VarTypes::Bool => {
340                        self.requires.push("stdbool.h");
341                        "bool "
342                    }
343                    VarTypes::Char => "char ",
344                });
345
346                self.code.push_str(name);
347
348                if let VarTypes::String = ty {
349                    self.code.push_str("[]");
350                }
351
352                self.code.push('=');
353                self.code.push_str(ident);
354                self.code.push(';');
355                self.code.push('\n');
356            }
357            VarInit::Bool(b) => {
358                self.requires.push("stdbool.h");
359
360                self.code.push_str("bool ");
361                self.code.push_str(name);
362
363                self.code.push('=');
364                self.code.push_str(&b.to_string());
365                self.code.push_str(";\n");
366            }
367            VarInit::Char(c) => {
368                self.code.push_str("char ");
369                self.code.push_str(name);
370
371                self.code.push_str("='");
372                self.code.push(c);
373                self.code.push_str("';\n");
374            }
375            VarInit::Double(f) => {
376                self.code.push_str("double ");
377                self.code.push_str(name);
378
379                self.code.push('=');
380                self.code.push_str(&f.to_string());
381                self.code.push_str(";\n");
382            }
383            VarInit::Float(f) => {
384                self.code.push_str("float ");
385                self.code.push_str(name);
386
387                self.code.push('=');
388                self.code.push_str(&f.to_string());
389                self.code.push_str(";\n");
390            }
391            VarInit::Int32(i) => {
392                self.code.push_str("int ");
393                self.code.push_str(name);
394
395                self.code.push('=');
396                self.code.push_str(&i.to_string());
397                self.code.push_str(";\n");
398            }
399            VarInit::Int64(i) => {
400                self.code.push_str("int ");
401                self.code.push_str(name);
402
403                self.code.push('=');
404                self.code.push_str(&i.to_string());
405                self.code.push_str(";\n");
406            }
407            VarInit::SizeString(size) => {
408                self.code.push_str("char ");
409                self.code.push_str(name);
410
411                self.code.push('[');
412                self.code.push_str(&size.to_string());
413                self.code.push_str("];\n");
414            }
415        }
416    }
417}
418
419impl Display for Code<'_> {
420    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
421        let mut require_string = String::new();
422
423        for require in &self.requires {
424            require_string.push_str("#include<");
425            require_string.push_str(require);
426            require_string.push_str(">\n");
427        }
428
429        writeln!(
430            f,
431            "{}int main() {{\n{}return {};\n}}",
432            require_string, self.code, self.exit
433        )
434    }
435}
436
437#[cfg(test)]
438mod tests {
439    use super::*;
440
441    #[test]
442    fn test_empty() {
443        let code = Code::new();
444
445        assert_eq!(code.to_string(), "int main() {\nreturn 0;\n}\n");
446    }
447
448    #[test]
449    fn test_exit_zero() {
450        let mut code = Code::new();
451
452        code.exit(0);
453
454        assert_eq!(code.to_string(), "int main() {\nreturn 0;\n}\n");
455    }
456
457    #[test]
458    fn test_exit_non_zero() {
459        let mut code = Code::new();
460
461        code.exit(1);
462
463        assert_eq!(code.to_string(), "int main() {\nreturn 1;\n}\n");
464    }
465
466    #[test]
467    fn test_multiple_exits() {
468        let mut code = Code::new();
469
470        code.exit(0);
471        code.exit(1);
472
473        assert_eq!(code.to_string(), "int main() {\nreturn 1;\n}\n");
474    }
475
476    #[test]
477    fn test_include_valid() {
478        let mut code = Code::new();
479
480        code.include("stdio.h");
481
482        assert!(code.to_string().contains("#include<stdio.h>"));
483    }
484
485    #[test]
486    fn test_func_no_args() {
487        let mut code = Code::new();
488
489        code.call_func("printf");
490
491        assert!(code.to_string().contains("printf();"));
492    }
493
494    #[test]
495    fn test_func_with_args() {
496        let mut code = Code::new();
497
498        code.call_func_with_args("printf", vec![CArg::String("Hello")]);
499
500        assert!(code.to_string().contains("printf(\"Hello\");"));
501    }
502
503    #[test]
504    fn test_variable_string() {
505        let mut code = Code::new();
506
507        code.new_var("msg", VarInit::String("Hello"));
508
509        assert!(code.to_string().contains("char msg[]=\"Hello\";"));
510    }
511
512    #[test]
513    fn test_variable_i32() {
514        let mut code = Code::new();
515
516        code.new_var("num", VarInit::Int32(i32::MAX));
517
518        assert!(code
519            .to_string()
520            .contains(format!("int num={};", i32::MAX).as_str()));
521    }
522
523    #[test]
524    fn test_variable_i64() {
525        let mut code = Code::new();
526
527        code.new_var("num", VarInit::Int64(i64::MAX));
528
529        assert!(code
530            .to_string()
531            .contains(format!("int num={};", i64::MAX).as_str()));
532    }
533
534    #[test]
535    fn test_variable_float() {
536        let mut code = Code::new();
537
538        code.new_var("num", VarInit::Float(f32::MAX));
539
540        assert!(code
541            .to_string()
542            .contains(format!("float num={};", f32::MAX).as_str()));
543    }
544
545    #[test]
546    fn test_variable_double() {
547        let mut code = Code::new();
548
549        code.new_var("num", VarInit::Double(f64::MAX));
550
551        assert!(code
552            .to_string()
553            .contains(format!("double num={};", f64::MAX).as_str()));
554    }
555
556    #[test]
557    fn test_variable_bool() {
558        let mut code = Code::new();
559
560        code.new_var("b", VarInit::Bool(true));
561
562        assert!(code.to_string().contains("bool b=true;"));
563    }
564
565    #[test]
566    fn test_variable_char() {
567        let mut code = Code::new();
568
569        code.new_var("c", VarInit::Char('c'));
570
571        assert!(code.to_string().contains("char c='c';"));
572    }
573
574    #[test]
575    fn test_variable_size_string() {
576        let mut code = Code::new();
577
578        code.new_var("msg", VarInit::SizeString(5));
579
580        assert!(code.to_string().contains("char msg[5];"));
581    }
582
583    #[test]
584    fn test_variable_ident() {
585        let mut code = Code::new();
586
587        code.new_var("s", VarInit::String("X"));
588        code.new_var("t", VarInit::Ident(VarTypes::String, "s"));
589
590        assert!(code.to_string().contains("char s[]=\"X\";\nchar t[]=s;"));
591    }
592}