aboutsummaryrefslogtreecommitdiffstats
path: root/letmein-conf/src/parse.rs
blob: 7c71a73d1f62b028fb9b5716301ae500b5fc982a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// -*- coding: utf-8 -*-
//
// Copyright (C) 2024 Michael Büsch <m@bues.ch>
//
// Licensed under the Apache License version 2.0
// or the MIT license, at your option.
// SPDX-License-Identifier: Apache-2.0 OR MIT

use anyhow::{self as ah, format_err as err};
use std::time::Duration;

pub fn parse_bool(s: &str) -> ah::Result<bool> {
    let s = s.to_lowercase();
    let s = s.trim();
    match s {
        "true" | "1" | "yes" | "on" => Ok(true),
        "false" | "0" | "no" | "off" => Ok(false),
        _ => Err(err!("Invalid boolean string")),
    }
}

pub fn parse_u16(s: &str) -> ah::Result<u16> {
    let s = s.trim();
    if let Some(s) = s.strip_prefix("0x") {
        Ok(u16::from_str_radix(s, 16)?)
    } else {
        Ok(s.parse::<u16>()?)
    }
}

fn parse_u32(s: &str) -> ah::Result<u32> {
    let s = s.trim();
    if let Some(s) = s.strip_prefix("0x") {
        Ok(u32::from_str_radix(s, 16)?)
    } else {
        Ok(s.parse::<u32>()?)
    }
}

fn parse_f64(s: &str) -> ah::Result<f64> {
    let s = s.trim();
    let value = s.parse::<f64>()?;
    if value.is_finite() {
        Ok(value)
    } else {
        Err(err!("Invalid floating point value (Inf or NaN)"))
    }
}

fn parse_hexdigit(s: &str) -> ah::Result<u8> {
    assert_eq!(s.len(), 1);
    Ok(u8::from_str_radix(s, 16)?)
}

pub fn parse_hex<const SIZE: usize>(s: &str) -> ah::Result<[u8; SIZE]> {
    let s = s.trim();
    if !s.is_ascii() {
        return Err(err!("Hex string contains invalid characters."));
    }
    let len = s.len();
    if len != SIZE * 2 {
        return Err(err!(
            "Hex string is too short: Expected {}, got {} chars",
            SIZE * 2,
            len,
        ));
    }
    let mut ret = [0; SIZE];
    for i in 0..SIZE {
        ret[i] = parse_hexdigit(&s[i * 2..i * 2 + 1])? << 4;
        ret[i] |= parse_hexdigit(&s[i * 2 + 1..i * 2 + 2])?;
    }
    Ok(ret)
}

pub fn parse_duration(s: &str) -> ah::Result<Duration> {
    if let Ok(secs) = parse_u32(s) {
        return Ok(Duration::from_secs(secs.into()));
    }
    if let Ok(secs) = parse_f64(s) {
        if secs >= 0.0 && secs <= u32::MAX.into() {
            return Ok(Duration::from_secs_f64(secs));
        }
    }
    Err(err!("Invalid Duration"))
}

// vim: ts=4 sw=4 expandtab
bues.ch cgit interface