xref: /aosp_15_r20/external/mesa3d/src/nouveau/headers/lib_rs_gen.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#! /usr/bin/env python3
2#
3# Copyright © 2024 Collabora Ltd. and Red Hat Inc.
4# SPDX-License-Identifier: MIT
5
6# This script takes a list of Rust files, each of the form nvh_path_to_mod.rs
7# and constructs a lib.rs which puts each of them in ::path::to::mod.
8
9import argparse
10import os.path
11import re
12import subprocess
13import sys
14
15from mako.template import Template
16
17TEMPLATE_RS = Template("""\
18// Copyright © 2024 Collabora Ltd. and Red Hat Inc.
19// SPDX-License-Identifier: MIT
20
21// This file is generated by lib_rs_gen.py. DO NOT EDIT!
22
23#![allow(unused_imports)]
24
25<%def name="import_mod(m, path)">
26% if m.present:
27mod nvh_${'_'.join(path)};
28% endif
29% for name in sorted(m.children):
30${import_mod(m.children[name], path + [name])}
31% endfor
32</%def>
33${import_mod(root, [])}
34
35<%def name="decl_mod(m, path)">
36% if path:
37pub mod ${path[-1]} {
38% endif
39
40% if m.present:
41pub use crate::nvh_${'_'.join(path)}::*;
42% endif
43
44% for name in sorted(m.children):
45${decl_mod(m.children[name], path + [name])}
46% endfor
47
48% if path:
49}
50% endif
51</%def>
52
53/// Converts a method to its raw representation.
54pub trait Mthd {
55    /// The hardware address of the method.
56    const ADDR: u16;
57    /// The class of the method.
58    const CLASS: u16;
59    /// Converts the method to its raw representation.
60    fn to_bits(self) -> u32;
61}
62
63pub trait ArrayMthd {
64    /// The class of the method.
65    const CLASS: u16;
66    /// The hardware address of the method for the given index.
67    fn addr(i: usize) -> u16;
68    /// Converts the method to its raw representation.
69    fn to_bits(self) -> u32;
70}
71
72${decl_mod(root, [])}
73""")
74
75class Mod(object):
76    def __init__(self):
77        self.present = False;
78        self.children = {}
79
80    def add_child(self, path):
81        mod = self
82        for p in path:
83            if p not in mod.children:
84                mod.children[p] = Mod()
85            mod = mod.children[p]
86
87        # Once we've found the child, mark it present
88        assert not mod.present
89        mod.present = True
90
91def main():
92    parser = argparse.ArgumentParser()
93    parser.add_argument('--out-rs', required=True, help='Output Rust file.')
94    parser.add_argument('class_files', metavar='FILE', nargs='*',
95                        action='append',
96                        help='Input class Rust filename')
97    args = parser.parse_args()
98
99    root = Mod()
100    for f in args.class_files[0]:
101        f = os.path.basename(f)
102        assert f.endswith('.rs')
103        f = f.removesuffix('.rs')
104
105        mod_path = f.split('_')
106        assert mod_path[0] == 'nvh'
107        root.add_child(mod_path[1:])
108
109    try:
110        with open(args.out_rs, 'w', encoding='utf-8') as f:
111            f.write(TEMPLATE_RS.render(root=root))
112            try:
113                subprocess.run(['rustfmt', args.out_rs], check=True)
114            except (subprocess.CalledProcessError, FileNotFoundError):
115                pass
116
117    except Exception:
118        # In the event there's an error, this imports some helpers from mako
119        # to print a useful stack trace and prints it, then exits with
120        # status 1, if python is run with debug; otherwise it just raises
121        # the exception
122        import sys
123        from mako import exceptions
124        print(exceptions.text_error_template().render(), file=sys.stderr)
125        sys.exit(1)
126
127if __name__ == '__main__':
128    main()
129