browscap_rs/
lib.rs

1use crate::error::ParseError;
2use crate::file_parser::FileParser;
3use crate::filter::Filter;
4use crate::rule::Rule;
5use std::fs::File;
6use std::io::BufReader;
7use hashbrown::HashSet;
8use ustr::Ustr;
9
10mod brows_cap_field;
11mod capabilities;
12mod error;
13mod mapper;
14mod rule;
15mod searchable_string;
16mod file_parser;
17pub mod user_agent_parser;
18mod filter;
19mod literal;
20
21// 枚举常量定义
22pub const IS_MASTER_PARENT: BrowsCapField = BrowsCapField::new("IS_MASTER_PARENT", false, 0);
23pub const IS_LITE_MODE: BrowsCapField = BrowsCapField::new("IS_LITE_MODE", false, 1);
24pub const PARENT: BrowsCapField = BrowsCapField::new("PARENT", false, 2);
25pub const COMMENT: BrowsCapField = BrowsCapField::new("COMMENT", false, 3);
26pub const BROWSER: BrowsCapField = BrowsCapField::new("BROWSER", true, 4);
27pub const BROWSER_TYPE: BrowsCapField = BrowsCapField::new("BROWSER_TYPE", true, 5);
28pub const BROWSER_BITS: BrowsCapField = BrowsCapField::new("BROWSER_BITS", false, 6);
29pub const BROWSER_MAKER: BrowsCapField = BrowsCapField::new("BROWSER_MAKER", false, 7);
30pub const BROWSER_MODUS: BrowsCapField = BrowsCapField::new("BROWSER_MODUS", false, 8);
31pub const BROWSER_VERSION: BrowsCapField = BrowsCapField::new("BROWSER_VERSION", false, 9);
32pub const BROWSER_MAJOR_VERSION: BrowsCapField = BrowsCapField::new("BROWSER_MAJOR_VERSION", true, 10);
33pub const BROWSER_MINOR_VERSION: BrowsCapField = BrowsCapField::new("BROWSER_MINOR_VERSION", false, 11);
34pub const PLATFORM: BrowsCapField = BrowsCapField::new("PLATFORM", true, 12);
35pub const PLATFORM_VERSION: BrowsCapField = BrowsCapField::new("PLATFORM_VERSION", true, 13);
36pub const PLATFORM_DESCRIPTION: BrowsCapField = BrowsCapField::new("PLATFORM_DESCRIPTION", false, 14);
37pub const PLATFORM_BITS: BrowsCapField = BrowsCapField::new("PLATFORM_BITS", false, 15);
38pub const PLATFORM_MAKER: BrowsCapField = BrowsCapField::new("PLATFORM_MAKER", false, 16);
39pub const IS_ALPHA: BrowsCapField = BrowsCapField::new("IS_ALPHA", false, 17);
40pub const IS_BETA: BrowsCapField = BrowsCapField::new("IS_BETA", false, 18);
41pub const IS_WIN16: BrowsCapField = BrowsCapField::new("IS_WIN16", false, 19);
42pub const IS_WIN32: BrowsCapField = BrowsCapField::new("IS_WIN32", false, 20);
43pub const IS_WIN64: BrowsCapField = BrowsCapField::new("IS_WIN64", false, 21);
44pub const IS_IFRAMES: BrowsCapField = BrowsCapField::new("IS_IFRAMES", false, 22);
45pub const IS_FRAMES: BrowsCapField = BrowsCapField::new("IS_FRAMES", false, 23);
46pub const IS_TABLES: BrowsCapField = BrowsCapField::new("IS_TABLES", false, 24);
47pub const IS_COOKIES: BrowsCapField = BrowsCapField::new("IS_COOKIES", false, 25);
48pub const IS_BACKGROUND_SOUNDS: BrowsCapField = BrowsCapField::new("IS_BACKGROUND_SOUNDS", false, 26);
49pub const IS_JAVASCRIPT: BrowsCapField = BrowsCapField::new("IS_JAVASCRIPT", false, 27);
50pub const IS_VBSCRIPT: BrowsCapField = BrowsCapField::new("IS_VBSCRIPT", false, 28);
51pub const IS_JAVA_APPLETS: BrowsCapField = BrowsCapField::new("IS_JAVA_APPLETS", false, 29);
52pub const IS_ACTIVEX_CONTROLS: BrowsCapField = BrowsCapField::new("IS_ACTIVEX_CONTROLS", false, 30);
53pub const IS_MOBILE_DEVICE: BrowsCapField = BrowsCapField::new("IS_MOBILE_DEVICE", false, 31);
54pub const IS_TABLET: BrowsCapField = BrowsCapField::new("IS_TABLET", false, 32);
55pub const IS_SYNDICATION_READER: BrowsCapField = BrowsCapField::new("IS_SYNDICATION_READER", false, 33);
56pub const IS_CRAWLER: BrowsCapField = BrowsCapField::new("IS_CRAWLER", false, 34);
57pub const IS_FAKE: BrowsCapField = BrowsCapField::new("IS_FAKE", false, 35);
58pub const IS_ANONYMIZED: BrowsCapField = BrowsCapField::new("IS_ANONYMIZED", false, 36);
59pub const IS_MODIFIED: BrowsCapField = BrowsCapField::new("IS_MODIFIED", false, 37);
60pub const CSS_VERSION: BrowsCapField = BrowsCapField::new("CSS_VERSION", false, 38);
61pub const AOL_VERSION: BrowsCapField = BrowsCapField::new("AOL_VERSION", false, 39);
62pub const DEVICE_NAME: BrowsCapField = BrowsCapField::new("DEVICE_NAME", false, 40);
63pub const DEVICE_MAKER: BrowsCapField = BrowsCapField::new("DEVICE_MAKER", false, 41);
64pub const DEVICE_TYPE: BrowsCapField = BrowsCapField::new("DEVICE_TYPE", true, 42);
65pub const DEVICE_POINTING_METHOD: BrowsCapField = BrowsCapField::new("DEVICE_POINTING_METHOD", false, 43);
66pub const DEVICE_CODE_NAME: BrowsCapField = BrowsCapField::new("DEVICE_CODE_NAME", false, 44);
67pub const DEVICE_BRAND_NAME: BrowsCapField = BrowsCapField::new("DEVICE_BRAND_NAME", false, 45);
68pub const RENDERING_ENGINE_NAME: BrowsCapField = BrowsCapField::new("RENDERING_ENGINE_NAME", false, 46);
69pub const RENDERING_ENGINE_VERSION: BrowsCapField = BrowsCapField::new("RENDERING_ENGINE_VERSION", false, 47);
70pub const RENDERING_ENGINE_DESCRIPTION: BrowsCapField = BrowsCapField::new("RENDERING_ENGINE_DESCRIPTION", false, 48);
71pub const RENDERING_ENGINE_MAKER: BrowsCapField = BrowsCapField::new("RENDERING_ENGINE_MAKER", false, 49);
72
73const DEFAULT_FILE_NAME: &'static str = "browscap_sorted.csv";
74
75pub trait Predicate<T> {
76    fn test(&self, value: &T) -> bool;
77}
78
79// 为函数指针实现
80impl<F, T> Predicate<T> for F
81where
82    F: Fn(&T) -> bool,
83{
84    fn test(&self, value: &T) -> bool {
85        self(value)
86    }
87}
88
89#[derive(Eq, Hash, PartialEq,Debug)]
90pub struct BrowsCapField {
91    name: &'static str,
92    is_default: bool,
93    ordinal: usize,
94}
95
96#[derive(Debug)]
97pub struct Capabilities {
98    my_values: Vec<Ustr>,
99}
100
101#[derive(Debug)]
102pub struct UserAgentParser {
103    my_rules: Vec<Rule>,
104    my_filters: Vec<Filter>,
105}
106
107
108pub fn load_parser_default() -> Result<UserAgentParser, ParseError> {
109    load_parser_with_fields(default_fields())
110}
111
112pub fn load_parser_with_fields(
113    fields: Vec<&'static BrowsCapField>,
114) -> Result<UserAgentParser, ParseError> {
115    create_parser_by_file(fields, DEFAULT_FILE_NAME)
116}
117
118pub fn create_parser_by_file(
119    fields: Vec<&'static BrowsCapField>,
120    file_name: & str
121) -> Result<UserAgentParser, ParseError> {
122    let file = File::open(file_name).unwrap();
123    let merged_unique_fields = merge_fields(fields);
124    let reader = BufReader::new(file);
125    let mut file_parser=FileParser::new(merged_unique_fields);
126    file_parser.parse(reader);
127    let user_agent_parser=file_parser::create_agent_parser(file_parser);
128    Ok(user_agent_parser)
129}
130
131 fn default_fields() -> Vec<&'static BrowsCapField> {
132    BrowsCapField::values()
133        .iter()
134        .filter(|i| i.is_default())
135        .collect()
136}
137
138fn merge_fields(fields: Vec<&'static BrowsCapField>) -> HashSet<&'static BrowsCapField> {
139    let mut unique_fields: HashSet<&BrowsCapField> = HashSet::new();
140    fields.into_iter().for_each(|i| {
141        unique_fields.insert(i);
142    });
143    default_fields().into_iter().for_each(|i| {
144        unique_fields.insert(i);
145    });
146    unique_fields
147}
148
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    #[test]
154    fn test_load_fields() {
155        let fields = default_fields();
156        for field in fields.iter() {
157            println!("{}", field.name());
158
159        }
160        println!("-------------");
161        assert_eq!(fields.len(), 6)
162    }
163
164    #[test]
165    fn test_merge_fields(){
166        let mut my_fields:Vec<&'static BrowsCapField>=Vec::new();
167        my_fields.push(&BROWSER);
168        my_fields.push(&IS_BETA);
169        my_fields.push(&PLATFORM);
170        let merge_fields = merge_fields(my_fields);
171        for merge_field in merge_fields.iter() {
172            println!("{}", merge_field.name())
173        }
174        println!("-------------");
175        assert_eq!(merge_fields.len(), 7)
176    }
177}