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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::iter::Enumerate;
use std::path::{Path, PathBuf};
use std::str::from_utf8;

pub type FnBlockReturnType = (usize, isize, Option<Vec<AdvReturnValue>>);

pub type FnReadBlockType = Option<
    Box<
        dyn Fn(
                Option<&[u8]>, // item
                &[u8],         // buffer
                &mut Enumerate<std::slice::Iter<'_, u8>>,
                usize,      // i
                u8,         // c
                &mut usize, // line_num
                u8,         // line_end
            ) -> FnBlockReturnType
            + Send
            + 'static,
    >,
>;

#[derive(PartialEq, Clone, Debug)]
pub enum ReaderState {
    Default,
    Number,
    String,
    LineComment,
    Comment,
    Block,
}

#[derive(Clone, Debug, PartialEq)]
pub enum AdvReturnValue {
    Bytes(Vec<u8>),
    String(Vec<u8>),
    Comment(Vec<u8>),
    LineComment(Vec<u8>),
    StringUtf8(String),
    CommentUtf8(String),
    LineCommentUtf8(String),
    Bool(bool),
    Int(i64),
    Float(f64),
    Hex(i64),
    Oct(i64),
    Bin(i64),
    Block(Vec<u8>),
}

impl AdvReturnValue {
    pub fn as_string(&self) -> String {
        match &self {
            AdvReturnValue::Bytes(v) => format!("Bytes({:?})", from_utf8(v)),
            AdvReturnValue::String(v) => format!("String({:?})", from_utf8(v)),
            AdvReturnValue::Comment(v) => format!("Comment({:?})", from_utf8(v)),
            AdvReturnValue::LineComment(v) => format!("LineComment({:?})", from_utf8(v)),
            AdvReturnValue::StringUtf8(v) => format!("StringUtf8({v})"),
            AdvReturnValue::CommentUtf8(v) => format!("CommentUtf8({v})"),
            AdvReturnValue::LineCommentUtf8(v) => format!("LineCommentUtf8({v})"),
            AdvReturnValue::Bool(v) => format!("Bool({v:?})"),
            AdvReturnValue::Int(v) => format!("Int({v:?})"),
            AdvReturnValue::Float(v) => format!("Float({v:?})"),
            AdvReturnValue::Hex(v) => format!("Hex({v:?})"),
            AdvReturnValue::Oct(v) => format!("Oct({v:?})"),
            AdvReturnValue::Bin(v) => format!("Bin({v:?})"),
            AdvReturnValue::Block(v) => format!("Block({:?})", from_utf8(v)),
        }
    }
}

#[derive(Debug)]
pub struct AdvReaderOptions {
    pub path: PathBuf,
    pub buffer_size: usize,
    pub trim: bool,
    pub line_end: u8,
    pub skip_comments: bool,
    /// Convert (Line) Comments into UTF8
    pub encode_comments: bool,
    /// Convert Strings into UTF8
    pub encode_strings: bool,
    /// Optional encoder for converting strings into UTF8
    pub encoder: Option<String>,
    /// Allow invalid UTF8 characters.
    pub allow_invalid_utf8: bool,
    /// Valid characters for word: 0-9a-zA-Z_.
    pub extended_word_separation: bool,
    /// Special support for escaping double quote is: ""
    pub double_quote_escape: bool,
    /// Convert text to numbers (int, float)
    pub convert2numbers: bool,
    /// Keep base of number
    pub keep_base: bool,
    /// If defined boolean False detection is enabled.
    pub bool_false: Option<Vec<u8>>,
    /// If defined boolean True detection is enabled.
    pub bool_true: Option<Vec<u8>>,
}

impl AdvReaderOptions {
    pub fn new(path: &Path, encoder: Option<String>) -> Self {
        Self {
            path: path.to_path_buf(),
            buffer_size: 65536,
            trim: false,
            line_end: b'\n',
            skip_comments: false,
            encode_comments: true,
            encode_strings: true,
            encoder,
            allow_invalid_utf8: true,
            extended_word_separation: false,
            double_quote_escape: false,
            convert2numbers: true,
            keep_base: false,
            bool_false: None,
            bool_true: None,
        }
    }
}