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
89
90
91
92
93
94
95
96
97
//! Parse encoding parameter to `Regexp#initialize` and `Regexp::compile`.

use std::hash::{Hash, Hasher};

use crate::extn::core::regexp::Regexp;
use crate::value::Value;

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum Error {
    InvalidEncoding,
}

#[derive(Debug, Clone, Copy)]
pub enum Encoding {
    Fixed,
    No,
    None,
}

impl Encoding {
    pub fn flags(self) -> i64 {
        match self {
            Encoding::Fixed => Regexp::FIXEDENCODING,
            Encoding::No => Regexp::NOENCODING,
            Encoding::None => 0,
        }
    }

    pub fn string(self) -> &'static str {
        match self {
            Encoding::Fixed | Encoding::None => "",
            Encoding::No => "n",
        }
    }
}

impl Default for Encoding {
    fn default() -> Self {
        Encoding::None
    }
}

impl Hash for Encoding {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.string().hash(state);
    }
}

impl PartialEq for Encoding {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Encoding::No, Encoding::None)
            | (Encoding::None, Encoding::No)
            | (Encoding::No, Encoding::No)
            | (Encoding::None, Encoding::None)
            | (Encoding::Fixed, Encoding::Fixed) => true,
            _ => false,
        }
    }
}

impl Eq for Encoding {}

pub fn parse(value: &Value) -> Result<Encoding, Error> {
    if let Ok(encoding) = value.itself::<i64>() {
        // Only deal with Encoding opts
        let encoding = encoding & !Regexp::ALL_REGEXP_OPTS;
        if encoding == Regexp::FIXEDENCODING {
            Ok(Encoding::Fixed)
        } else if encoding == Regexp::NOENCODING {
            Ok(Encoding::No)
        } else if encoding == 0 {
            Ok(Encoding::default())
        } else {
            Err(Error::InvalidEncoding)
        }
    } else if let Ok(encoding) = value.itself::<String>() {
        if encoding.contains('u') && encoding.contains('n') {
            return Err(Error::InvalidEncoding);
        }
        let mut enc = vec![];
        for flag in encoding.chars() {
            match flag {
                'u' | 's' | 'e' => enc.push(Encoding::Fixed),
                'n' => enc.push(Encoding::No),
                'i' | 'm' | 'x' | 'o' => continue,
                _ => return Err(Error::InvalidEncoding),
            }
        }
        if enc.len() > 1 {
            return Err(Error::InvalidEncoding);
        }
        Ok(enc.pop().unwrap_or_default())
    } else {
        Ok(Encoding::default())
    }
}