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

zhiburt / tabled / 11433508586

21 Oct 2024 05:00AM UTC coverage: 74.214% (-0.006%) from 74.22%
11433508586

push

github

web-flow
Merge pull request #428 from welpo/fix/migrate-to-proc-macro-error2

fix(deps): migrate from proc-macro-error to proc-macro-error2

0 of 7 new or added lines in 2 files covered. (0.0%)

1 existing line in 1 file now uncovered.

12246 of 16501 relevant lines covered (74.21%)

2.2 hits per line

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

0.0
/static_table/src/pool_table.rs
1
use quote::ToTokens;
2
use syn::{
3
    bracketed,
4
    parse::{Parse, ParseStream},
5
    punctuated::Punctuated,
6
    token::{self},
7
    ExprLit, Ident, Lit, LitInt, LitStr, Result, Token,
8
};
9
use tabled::{
10
    settings::{Alignment, Margin, Padding, Style},
11
    tables::{PoolTable, TableValue},
12
};
13

14
struct MatrixRow {
15
    #[allow(dead_code)]
16
    bracket_token: token::Bracket,
17
    elems: MatrixRowElements,
18
}
19

20
enum MatrixRowElements {
21
    List(Punctuated<ExprLit, Token![,]>),
22
    Static {
23
        elem: ExprLit,
24
        #[allow(dead_code)]
25
        semi_token: Token![;],
26
        len: LitInt,
27
    },
28
}
29

30
impl Parse for MatrixRow {
31
    fn parse(input: ParseStream<'_>) -> Result<Self> {
×
32
        let content;
×
33
        let bracket_token = bracketed!(content in input);
×
34

35
        if content.peek2(Token![;]) {
×
36
            return Ok(Self {
×
37
                bracket_token,
×
38
                elems: MatrixRowElements::Static {
×
39
                    elem: content.parse()?,
×
40
                    semi_token: content.parse()?,
×
41
                    len: content.parse()?,
×
42
                },
43
            });
44
        }
45

46
        let mut elems = Punctuated::new();
×
47
        while !content.is_empty() {
×
48
            let val = content.parse()?;
×
49
            elems.push_value(val);
×
50
            if content.is_empty() {
×
51
                break;
×
52
            }
53
            let punct = content.parse()?;
×
54
            elems.push_punct(punct);
×
55
        }
56

57
        Ok(Self {
×
58
            bracket_token,
×
59
            elems: MatrixRowElements::List(elems),
×
60
        })
61
    }
62
}
63

64
struct MatrixInput {
65
    #[allow(dead_code)]
66
    bracket_token: token::Bracket,
67
    data: MatrixData,
68
}
69

70
enum MatrixData {
71
    List(Punctuated<MatrixRow, Token![,]>),
72
    Static {
73
        elem: MatrixRow,
74
        #[allow(dead_code)]
75
        semi_token: Token![;],
76
        len: LitInt,
77
    },
78
}
79

80
impl Parse for MatrixInput {
81
    fn parse(input: ParseStream<'_>) -> Result<Self> {
×
82
        let content;
×
83
        let bracket_token = bracketed!(content in input);
×
84

85
        if content.is_empty() {
×
86
            return Ok(Self {
×
87
                bracket_token,
×
88
                data: MatrixData::List(Punctuated::new()),
×
89
            });
90
        }
91

92
        let elem = content.parse()?;
×
93

94
        if content.peek(Token![;]) {
×
95
            return Ok(MatrixInput {
×
96
                bracket_token,
×
97
                data: MatrixData::Static {
×
98
                    elem,
×
99
                    semi_token: content.parse()?,
×
100
                    len: content.parse()?,
×
101
                },
102
            });
103
        }
104

105
        let mut elems = Punctuated::new();
×
106
        elems.push(elem);
×
107

108
        while !content.is_empty() {
×
109
            let punct: Token![,] = content.parse()?;
×
110
            elems.push_punct(punct);
×
111

112
            if content.is_empty() {
×
113
                // trailing comma
114
                break;
×
115
            }
116

117
            let val = content.parse()?;
×
118
            elems.push_value(val);
×
119
        }
120

121
        Ok(MatrixInput {
×
122
            bracket_token,
×
123
            data: MatrixData::List(elems),
×
124
        })
125
    }
126
}
127

128
struct KeyValue<V> {
129
    key: Ident,
130
    #[allow(dead_code)]
131
    token: Token!(=),
132
    value: V,
133
}
134

135
impl<V: Parse> Parse for KeyValue<V> {
136
    fn parse(input: ParseStream<'_>) -> Result<Self> {
×
137
        Ok(Self {
×
138
            key: input.parse()?,
×
139
            token: input.parse()?,
×
140
            value: input.parse()?,
×
141
        })
142
    }
143
}
144

145
pub(crate) struct TableStruct {
146
    matrix: MatrixInput,
147
    comma_token: Option<Token![,]>,
148
    settings: Punctuated<KeyValue<LitStr>, Token!(,)>,
149
}
150

151
impl Parse for TableStruct {
152
    fn parse(input: ParseStream<'_>) -> Result<Self> {
×
153
        let matrix = input.parse()?;
×
154
        let mut comma_token = None;
×
155
        let mut settings = Punctuated::new();
×
156

157
        if input.peek(Token![,]) {
×
158
            comma_token = Some(input.parse()?);
×
159
            while !input.is_empty() {
×
160
                let val = input.parse()?;
×
161
                settings.push_value(val);
×
162
                if input.is_empty() {
×
163
                    break;
×
164
                }
165
                let punct = input.parse()?;
×
166
                settings.push_punct(punct);
×
167
            }
168
        }
169

170
        Ok(Self {
×
171
            matrix,
×
172
            comma_token,
×
173
            settings,
×
174
        })
175
    }
176
}
177

178
struct Pad<T> {
179
    left: T,
180
    #[allow(dead_code)]
181
    comma1_tk: Token!(,),
182
    right: T,
183
    #[allow(dead_code)]
184
    comma2_tk: Token!(,),
185
    top: T,
186
    #[allow(dead_code)]
187
    comma3_tk: Token!(,),
188
    bottom: T,
189
}
190

191
impl<T: Parse> Parse for Pad<T> {
192
    fn parse(input: ParseStream<'_>) -> Result<Self> {
×
193
        Ok(Self {
×
194
            left: input.parse()?,
×
195
            comma1_tk: input.parse()?,
×
196
            right: input.parse()?,
×
197
            comma2_tk: input.parse()?,
×
198
            top: input.parse()?,
×
199
            comma3_tk: input.parse()?,
×
200
            bottom: input.parse()?,
×
201
        })
202
    }
203
}
204

205
fn expr_lit_to_string(expr_lit: &ExprLit) -> String {
×
206
    match &expr_lit.lit {
×
207
        Lit::Str(val) => val.value(),
×
208
        Lit::ByteStr(val) => format!("{:?}", val.value()),
×
209
        Lit::Int(val) => val.base10_digits().to_string(),
×
210
        Lit::Float(val) => val.base10_digits().to_string(),
×
211
        Lit::Char(val) => val.value().to_string(),
×
212
        Lit::Byte(val) => val.value().to_string(),
×
213
        Lit::Bool(val) => val.value().to_string(),
×
214
        Lit::Verbatim(val) => val.to_token_stream().to_string(),
×
215
    }
216
}
217

218
fn collect_matrix(matrix: &MatrixInput) -> Result<Vec<Vec<String>>> {
×
219
    match &matrix.data {
×
220
        MatrixData::List(list) => {
×
221
            let mut data = vec![];
×
222
            for row in list {
×
223
                let row = collect_row(&row.elems)?;
×
224
                data.push(row)
×
225
            }
226

227
            Ok(data)
×
228
        }
229
        MatrixData::Static { elem, len, .. } => {
×
230
            let data = collect_row(&elem.elems)?;
×
231
            let len = len.base10_parse::<usize>()?;
×
232

233
            Ok(vec![data; len])
×
234
        }
235
    }
236
}
237

238
fn collect_row(elems: &MatrixRowElements) -> Result<Vec<String>> {
×
239
    match elems {
×
240
        MatrixRowElements::List(list) => {
×
241
            let mut row = Vec::with_capacity(list.len());
×
242
            for val in list {
×
243
                let val = expr_lit_to_string(val);
×
244
                row.push(val);
×
245
            }
246

247
            Ok(row)
×
248
        }
249
        MatrixRowElements::Static { elem, len, .. } => {
×
250
            let len = len.base10_parse::<usize>()?;
×
251
            let elem = expr_lit_to_string(elem);
×
252
            let row = vec![elem; len];
×
253

254
            Ok(row)
×
255
        }
256
    }
257
}
258

259
// todo: export the constants from crate so they could be highlighted by language servers.
260
// Yet this is unstable to do.
261
fn is_supported_theme(name: &str) -> bool {
×
262
    matches!(
×
263
        name,
264
        "EMPTY"
265
            | "BLANK"
266
            | "ASCII"
267
            | "ASCII_ROUNDED"
268
            | "DOTS"
269
            | "MODERN"
270
            | "SHARP"
271
            | "ROUNDED"
272
            | "EXTENDED"
273
            | "RE_STRUCTURED_TEXT"
274
            | "MARKDOWN"
275
            | "PSQL"
276
    )
277
}
278

279
fn apply_theme(table: &mut PoolTable, name: &str) {
×
280
    match name {
281
        "EMPTY" => table.with(Style::empty()),
×
282
        "BLANK" => table.with(Style::blank()),
×
283
        "ASCII" => table.with(Style::ascii()),
×
284
        "ASCII_ROUNDED" => table.with(Style::ascii_rounded()),
×
285
        "DOTS" => table.with(Style::dots()),
×
286
        "MODERN" => table.with(Style::modern()),
×
287
        "SHARP" => table.with(Style::sharp()),
×
288
        "ROUNDED" => table.with(Style::rounded()),
×
289
        "EXTENDED" => table.with(Style::extended()),
×
290
        "RE_STRUCTURED_TEXT" => table.with(Style::re_structured_text()),
×
291
        "MARKDOWN" => table.with(Style::markdown()),
×
292
        "PSQL" => table.with(Style::psql()),
×
293
        _ => unreachable!(),
294
    };
295
}
296

297
fn build_padding(pad: Pad<LitInt>) -> syn::Result<Padding> {
×
298
    let left = pad.left.base10_parse::<usize>()?;
×
299
    let right = pad.right.base10_parse::<usize>()?;
×
300
    let top = pad.top.base10_parse::<usize>()?;
×
301
    let bottom = pad.bottom.base10_parse::<usize>()?;
×
302

303
    Ok(Padding::new(left, right, top, bottom))
×
304
}
305

306
fn build_margin(pad: Pad<LitInt>) -> syn::Result<Margin> {
×
307
    let left = pad.left.base10_parse::<usize>()?;
×
308
    let right = pad.right.base10_parse::<usize>()?;
×
309
    let top = pad.top.base10_parse::<usize>()?;
×
310
    let bottom = pad.bottom.base10_parse::<usize>()?;
×
311

312
    Ok(Margin::new(left, right, top, bottom))
×
313
}
314

315
fn panic_not_supported_theme(ident: &LitStr) {
×
NEW
316
    proc_macro_error2::abort!(
×
317
        ident,
318
        "The given settings is not supported";
319
        note="custom themes are yet not supported";
320
        help = r#"Supported themes are [EMPTY, BLANK, ASCII, ASCII_ROUNDED, DOTS, MODERN, SHARP, ROUNDED, EXTENDED, RE_STRUCTURED_TEXT, MARKDOWN, PSQL]"#
321
    )
322
}
323

324
fn panic_not_supported_alignment(ident: &LitStr) {
×
NEW
325
    proc_macro_error2::abort!(
×
326
        ident,
327
        "The given settings is not supported";
328
        note="custom themes are yet not supported";
329
        help = r#"Supported alignment are [LEFT, RIGHT, CENTER, CENTER_VERTICAL, TOP, BOTTOM]"#
330
    )
331
}
332

333
fn panic_not_supported_settings(ident: &Ident) {
×
NEW
334
    proc_macro_error2::abort!(
×
335
        ident,
336
        "The given settings is not supported";
337
        help = r#"Supported list is [THEME, PADDING, MARGIN]"#
338
    )
339
}
340

341
pub(crate) fn build_table(table_st: &TableStruct) -> Result<String> {
×
342
    let mut table = create_table(&table_st.matrix)?;
×
343

344
    if table_st.comma_token.is_some() {
×
345
        apply_settings(&mut table, &table_st.settings)?;
×
346
    }
347

348
    Ok(table.to_string())
×
349
}
350

351
fn apply_settings(
×
352
    table: &mut PoolTable,
353
    settings: &Punctuated<KeyValue<LitStr>, Token![,]>,
354
) -> Result<()> {
355
    for kv in settings {
×
356
        config_table(table, kv)?;
×
357
    }
358

359
    Ok(())
×
360
}
361

362
fn is_supported_alignment(name: &str) -> bool {
×
363
    matches!(
×
364
        name,
365
        "LEFT" | "RIGHT" | "CENTER" | "CENTER_VERTICAL" | "TOP" | "BOTTOM"
366
    )
367
}
368

369
fn apply_alignment(table: &mut PoolTable, name: &str) {
×
370
    match name {
371
        "LEFT" => table.with(Alignment::left()),
×
372
        "RIGHT" => table.with(Alignment::right()),
×
373
        "CENTER" => table.with(Alignment::center()),
×
374
        "CENTER_VERTICAL" => table.with(Alignment::center_vertical()),
×
375
        "TOP" => table.with(Alignment::top()),
×
376
        "BOTTOM" => table.with(Alignment::bottom()),
×
377
        _ => unreachable!(),
378
    };
379
}
380

381
fn config_table(table: &mut PoolTable, kv: &KeyValue<LitStr>) -> Result<()> {
×
382
    if kv.key == "THEME" {
×
383
        let theme = kv.value.value();
×
384
        if !is_supported_theme(&theme) {
×
385
            panic_not_supported_theme(&kv.value);
×
386
        }
387

388
        apply_theme(table, &theme);
×
389
    } else if kv.key == "PADDING" {
×
390
        let padding = kv.value.parse().and_then(build_padding)?;
×
391
        table.with(padding);
×
392
    } else if kv.key == "MARGIN" {
×
393
        let margin = kv.value.parse().and_then(build_margin)?;
×
394
        table.with(margin);
×
395
    } else if kv.key == "ALIGNMENT" {
×
396
        let alignment = kv.value.value();
×
397
        if !is_supported_alignment(&alignment) {
×
398
            panic_not_supported_alignment(&kv.value);
×
399
        }
400

401
        apply_alignment(table, &alignment);
×
402
    } else {
403
        panic_not_supported_settings(&kv.key);
×
404
    }
405

406
    Ok(())
×
407
}
408

409
fn create_table(mat: &MatrixInput) -> Result<PoolTable> {
×
410
    let data = collect_matrix(mat)?;
×
411
    let value = matrix_to_table_value(data);
×
412
    Ok(PoolTable::from(value))
×
413
}
414

415
fn matrix_to_table_value(m: Vec<Vec<String>>) -> TableValue {
×
416
    TableValue::Column(
417
        m.into_iter()
×
418
            .map(|row| TableValue::Row(row.into_iter().map(TableValue::Cell).collect()))
×
419
            .collect(),
420
    )
421
}
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