]> git.proxmox.com Git - rustc.git/blame - vendor/xflags-macros/src/update.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / vendor / xflags-macros / src / update.rs
CommitLineData
064997fb
FG
1use std::{fs, ops::Range, path::Path};
2
3pub(crate) fn in_place(api: &str, path: &Path) {
4 let path = {
5 let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
6 Path::new(&dir).join(path)
7 };
8
2b03887a 9 let mut text = fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read {path:?}"));
064997fb
FG
10
11 let (insert_to, indent) = locate(&text);
12
13 let api: String =
14 with_preamble(api)
15 .lines()
16 .map(|it| {
17 if it.trim().is_empty() {
18 "\n".to_string()
19 } else {
20 format!("{}{}\n", indent, it)
21 }
22 })
23 .collect();
24 text.replace_range(insert_to, &api);
25
26 fs::write(&path, text.as_bytes()).unwrap();
27}
28
29pub(crate) fn stdout(api: &str) {
30 print!("{}", with_preamble(api))
31}
32
33fn with_preamble(api: &str) -> String {
34 format!(
35 "\
36// generated start
37// The following code is generated by `xflags` macro.
38// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
39{}
40// generated end
41",
42 api.trim()
43 )
44}
45
46fn locate(text: &str) -> (Range<usize>, String) {
47 if let Some(it) = locate_existing(text) {
48 return it;
49 }
50 if let Some(it) = locate_new(text) {
51 return it;
52 }
53 panic!("failed to update xflags in place")
54}
55
56fn locate_existing(text: &str) -> Option<(Range<usize>, String)> {
57 let start_idx = text.find("// generated start")?;
58 let start_idx = newline_before(text, start_idx);
59
60 let end_idx = text.find("// generated end")?;
61 let end_idx = newline_after(text, end_idx);
62
63 let indent = indent_at(text, start_idx);
64
65 Some((start_idx..end_idx, indent))
66}
67
68fn newline_before(text: &str, start_idx: usize) -> usize {
69 text[..start_idx].rfind('\n').map_or(start_idx, |it| it + 1)
70}
71
72fn newline_after(text: &str, start_idx: usize) -> usize {
73 start_idx + text[start_idx..].find('\n').map_or(text[start_idx..].len(), |it| it + 1)
74}
75
76fn indent_at(text: &str, start_idx: usize) -> String {
77 text[start_idx..].chars().take_while(|&it| it == ' ').collect()
78}
79
80fn locate_new(text: &str) -> Option<(Range<usize>, String)> {
81 let mut idx = text.find("xflags!")?;
82 let mut lvl = 0i32;
83 for c in text[idx..].chars() {
84 idx += c.len_utf8();
85 match c {
86 '{' => lvl += 1,
87 '}' if lvl == 1 => break,
88 '}' => lvl -= 1,
89 _ => (),
90 }
91 }
92 let indent = indent_at(text, newline_before(text, idx));
93 if text[idx..].starts_with('\n') {
94 idx += 1;
95 }
96 Some((idx..idx, indent))
97}