• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

chrjabs / rustsat / 16648222198

31 Jul 2025 11:52AM UTC coverage: 60.806% (+0.02%) from 60.791%
16648222198

push

github

web-flow
fix(encodings): totdb only reserve variables the connection needs (#435)

fixes #165

31 of 44 new or added lines in 5 files covered. (70.45%)

4 existing lines in 3 files now uncovered.

14318 of 23547 relevant lines covered (60.81%)

48096.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/codegen/src/main.rs
1
use std::io::Write;
2

3
use minijinja::{context, Environment};
4

5
fn main() {
×
6
    // Check if current directory has a Cargo.toml with [workspace]
×
7
    let cargo_toml_path = std::env::current_dir().unwrap().join("Cargo.toml");
×
8
    let cargo_toml_content =
×
9
        std::fs::read_to_string(cargo_toml_path).expect("Failed to read Cargo.toml");
×
10
    if !cargo_toml_content.contains("[workspace]") {
×
11
        panic!(
×
12
            "Cargo.toml does not contain [workspace] (you must run codegen from the workspace root)"
×
13
        );
14
    }
×
15

×
16
    let templates = template_env();
×
17

×
18
    let am1_encs = [
×
19
        Am1 {
×
20
            name: "Pairwise",
×
21
            id: "pairwise",
×
22
            wrapped: false,
×
23
            n_vars: 4,
×
24
            n_clauses: 6,
×
25
        },
×
26
        Am1 {
×
27
            name: "Ladder",
×
28
            id: "ladder",
×
29
            wrapped: false,
×
30
            n_vars: 7,
×
31
            n_clauses: 8,
×
32
        },
×
33
        Am1 {
×
34
            name: "Bitwise",
×
35
            id: "bitwise",
×
36
            wrapped: false,
×
37
            n_vars: 6,
×
38
            n_clauses: 8,
×
39
        },
×
40
        Am1 {
×
41
            name: "Commander",
×
42
            id: "commander",
×
43
            wrapped: true,
×
44
            n_vars: 5,
×
45
            n_clauses: 10,
×
46
        },
×
47
        Am1 {
×
48
            name: "Bimander",
×
49
            id: "bimander",
×
50
            wrapped: true,
×
51
            n_vars: 5,
×
52
            n_clauses: 10,
×
53
        },
×
54
    ];
×
55
    let path = "capi/src/encodings/am1.rs";
×
56
    capi_enc_bindings(path, "capi-am1.rs.j2", &am1_encs, &templates)
×
57
        .expect("failed to write am1 bindings");
×
58
    rustfmt(path);
×
59
    capi_tests("am1", &am1_encs, &templates).expect("failed to write am1 tests");
×
60

×
61
    let card_encs = [Card {
×
62
        name: "Totalizer",
×
63
        id: "tot",
×
64
        ub: true,
×
65
        lb: true,
×
66
        n_vars: 12,
×
67
        n_clauses: 28,
×
68
    }];
×
69
    let path = "capi/src/encodings/card.rs";
×
70
    capi_enc_bindings(path, "capi-card.rs.j2", &card_encs, &templates)
×
71
        .expect("failed to write card bindings");
×
72
    rustfmt(path);
×
73
    capi_tests("card", &card_encs, &templates).expect("failed to write card tests");
×
74

×
75
    let pb_encs = [
×
76
        Pb {
×
77
            name: "GeneralizedTotalizer",
×
78
            id: "gte",
×
79
            ub: true,
×
80
            lb: false,
×
81
            extend: true,
×
82
            n_vars: 24,
×
83
            n_vars_reserve: 24,
×
84
            n_clauses: 25,
×
85
            skip_reserve: false,
×
86
        },
×
87
        Pb {
×
88
            name: "BinaryAdder",
×
89
            id: "bin_adder",
×
90
            ub: true,
×
91
            lb: true,
×
92
            extend: true,
×
93
            n_vars: 20,
×
94
            n_vars_reserve: 20,
×
95
            n_clauses: 53,
×
96
            skip_reserve: true,
×
97
        },
×
98
        Pb {
×
99
            name: "DynamicPolyWatchdog",
×
100
            id: "dpw",
×
101
            ub: true,
×
102
            lb: false,
×
103
            extend: false,
×
104
            n_vars: 19,
×
NEW
105
            n_vars_reserve: 19,
×
106
            n_clauses: 21,
×
107
            skip_reserve: false,
×
108
        },
×
109
    ];
×
110
    let path = "capi/src/encodings/pb.rs";
×
111
    capi_enc_bindings(path, "capi-pb.rs.j2", &pb_encs, &templates)
×
112
        .expect("failed to write pb bindings");
×
113
    rustfmt(path);
×
114
    capi_tests("pb", &pb_encs, &templates).expect("failed to write pb tests");
×
115

×
116
    capi_header();
×
117
}
×
118

119
fn template_env() -> Environment<'static> {
×
120
    let mut env = Environment::new();
×
121
    env.set_loader(minijinja::path_loader("codegen/templates"));
×
122
    env
×
123
}
×
124

125
fn file(path: &str) -> impl std::io::Write {
×
126
    std::io::BufWriter::new(std::fs::File::create(path).expect("could not open file"))
×
127
}
×
128

129
/// Runs `rustfmt` on a generated file
130
fn rustfmt(path: &str) {
×
131
    let status = std::process::Command::new("rustfmt")
×
132
        .arg(path)
×
133
        .status()
×
134
        .expect("Failed to execute rustfmt");
×
135

×
136
    if !status.success() {
×
137
        eprintln!("rustfmt failed on file {path} with exit code: {status}");
×
138
    }
×
139
}
×
140

141
/// Runs `clang-format` on a generated file
142
fn clang_format(path: &str) {
×
143
    let status = std::process::Command::new("clang-format")
×
144
        .args(["-i", path])
×
145
        .status()
×
146
        .expect("Failed to execute clang-format");
×
147

×
148
    if !status.success() {
×
149
        eprintln!("clang-format failed on file {path} with exit code: {status}");
×
150
    }
×
151
}
×
152

153
fn capi_enc_bindings<E: Enc>(
×
154
    path: &str,
×
155
    template: &str,
×
156
    encs: &[E],
×
157
    templates: &Environment<'static>,
×
158
) -> std::io::Result<()> {
×
159
    let mut writer = file(path);
×
160
    let tmpl = templates.get_template(template).expect("missing template");
×
161
    let ub = encs.iter().any(|enc| enc.ub());
×
162
    let lb = encs.iter().any(|enc| enc.lb());
×
163
    writeln!(
×
164
        writer,
×
165
        "{}",
×
166
        tmpl.render(context!(encodings => encs, ub => ub, lb => lb))
×
167
            .expect("missing template context")
×
168
    )
×
169
}
×
170

171
fn capi_tests<E: Enc>(
×
172
    id: &str,
×
173
    encs: &[E],
×
174
    templates: &Environment<'static>,
×
175
) -> std::io::Result<()> {
×
176
    for entry in std::fs::read_dir("codegen/templates/").expect("failed to iteratre over template")
×
177
    {
178
        let entry = entry.unwrap();
×
179
        let file_type = entry.file_type().unwrap();
×
180
        if file_type.is_file() {
×
181
            let filename = entry.file_name();
×
182
            let filename = filename.to_str().unwrap();
×
183
            if let Some(name) = filename.strip_prefix(&format!("capi-{id}-test-")) {
×
184
                let name = name.trim_end_matches(".j2");
×
185
                let tmpl = templates.get_template(filename).expect("missing template");
×
186
                for enc in encs {
×
187
                    if enc.skip(name) {
×
188
                        continue;
×
189
                    }
×
190
                    let path = format!("capi/tests/{}-{name}", enc.id());
×
191
                    let mut writer = file(&path);
×
192
                    writeln!(
×
193
                        writer,
×
194
                        "{}",
×
195
                        tmpl.render(context!(enc => enc))
×
196
                            .expect("missing template context")
×
197
                    )?;
×
198
                    drop(writer);
×
199
                    clang_format(&path);
×
200
                }
201
            }
×
202
        }
×
203
    }
204
    Ok(())
×
205
}
×
206

207
trait Enc: serde::Serialize {
208
    fn id(&self) -> &str;
209
    fn ub(&self) -> bool {
×
210
        false
×
211
    }
×
212
    fn lb(&self) -> bool {
×
213
        false
×
214
    }
×
215
    fn skip(&self, _key: &str) -> bool {
×
216
        false
×
217
    }
×
218
}
219

220
#[derive(serde::Serialize)]
221
struct Am1<'a> {
222
    name: &'a str,
223
    id: &'a str,
224
    wrapped: bool,
225
    n_vars: u32,
226
    n_clauses: usize,
227
}
228

229
impl Enc for Am1<'_> {
230
    fn id(&self) -> &str {
×
231
        self.id
×
232
    }
×
233
}
234

235
#[derive(serde::Serialize)]
236
struct Card<'a> {
237
    name: &'a str,
238
    id: &'a str,
239
    ub: bool,
240
    lb: bool,
241
    n_vars: u32,
242
    n_clauses: usize,
243
}
244

245
impl Enc for Card<'_> {
246
    fn id(&self) -> &str {
×
247
        self.id
×
248
    }
×
249
    fn ub(&self) -> bool {
×
250
        self.ub
×
251
    }
×
252
    fn lb(&self) -> bool {
×
253
        self.lb
×
254
    }
×
255
}
256

257
#[derive(serde::Serialize)]
258
struct Pb<'a> {
259
    name: &'a str,
260
    id: &'a str,
261
    ub: bool,
262
    lb: bool,
263
    extend: bool,
264
    n_vars: u32,
265
    n_vars_reserve: u32,
266
    n_clauses: usize,
267
    skip_reserve: bool,
268
}
269

270
impl Enc for Pb<'_> {
271
    fn id(&self) -> &str {
×
272
        self.id
×
273
    }
×
274
    fn ub(&self) -> bool {
×
275
        self.ub
×
276
    }
×
277
    fn lb(&self) -> bool {
×
278
        self.lb
×
279
    }
×
280
    fn skip(&self, key: &str) -> bool {
×
281
        if key == "reserve.c" {
×
282
            return self.skip_reserve;
×
283
        }
×
284
        false
×
285
    }
×
286
}
287

288
/// Generates the C-API header
289
fn capi_header() {
×
290
    cbindgen::Builder::new()
×
291
        .with_config(
×
292
            cbindgen::Config::from_file("capi/cbindgen.toml")
×
293
                .expect("could not read cbindgen.toml"),
×
294
        )
×
295
        .with_crate("capi")
×
296
        .with_after_include(format!(
×
297
            r#"#define RUSTSAT_VERSION {version}
×
298
#define RUSTSAT_VERSION_MAJOR {major}
×
299
#define RUSTSAT_VERSION_MINOR {minor}
×
300
#define RUSTSAT_VERSION_PATCH {patch}"#,
×
301
            version = env!("CARGO_PKG_VERSION"),
×
302
            major = env!("CARGO_PKG_VERSION_MAJOR"),
×
303
            minor = env!("CARGO_PKG_VERSION_MINOR"),
×
304
            patch = env!("CARGO_PKG_VERSION_PATCH"),
×
305
        ))
×
306
        .generate()
×
307
        .expect("Unable to generate bindings")
×
308
        .write_to_file("capi/rustsat.h");
×
309
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc