phonenumber_fixed/metadata/
database.rs

1// Copyright (C) 2017 1aim GmbH
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::path::Path;
16use std::fs::File;
17use std::io::{Cursor, BufReader};
18use std::borrow::Borrow;
19use std::hash::Hash;
20use std::sync::{Arc, Mutex};
21
22use bincode::Options;
23use fnv::FnvHashMap;
24use regex_cache::{RegexCache, CachedRegex, CachedRegexBuilder};
25use bincode;
26
27use crate::error;
28use crate::metadata::loader;
29
30const DATABASE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/database.bin"));
31
32lazy_static! {
33	/// The Google provided metadata database, used as default.
34	pub static ref DEFAULT: Database =
35		Database::from(bincode::options()
36		.with_varint_encoding().deserialize(DATABASE).unwrap()).unwrap();
37}
38
39/// Representation of a database of metadata for phone number.
40#[derive(Clone, Debug)]
41pub struct Database {
42	cache:   Arc<Mutex<RegexCache>>,
43	by_id:   FnvHashMap<String, Arc<super::Metadata>>,
44	by_code: FnvHashMap<u16, Vec<Arc<super::Metadata>>>,
45	regions: FnvHashMap<u16, Vec<String>>,
46}
47
48impl Database {
49	/// Load a database from the given file.
50	pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, error::LoadMetadata> {
51		Database::from(loader::load(BufReader::new(File::open(path)?))?)
52	}
53
54	/// Parse a database from the given string.
55	pub fn parse<S: AsRef<str>>(content: S) -> Result<Self, error::LoadMetadata> {
56		Database::from(loader::load(Cursor::new(content.as_ref()))?)
57	}
58
59	/// Create a database from a loaded database.
60	pub fn from(meta: Vec<loader::Metadata>) -> Result<Self, error::LoadMetadata> {
61		fn tranpose<T, E>(value: Option<Result<T, E>>) -> Result<Option<T>, E> {
62			match value {
63				None =>
64					Ok(None),
65
66				Some(Ok(value)) =>
67					Ok(Some(value)),
68
69				Some(Err(err)) =>
70					Err(err),
71			}
72		}
73
74		let cache = Arc::new(Mutex::new(RegexCache::new(100)));
75		let regex = |value: String| -> Result<CachedRegex, error::LoadMetadata> {
76			Ok(CachedRegexBuilder::new(cache.clone(), &value)
77				.ignore_whitespace(true).build()?)
78		};
79
80		let descriptor = |desc: loader::Descriptor| -> Result<super::Descriptor, error::LoadMetadata> {
81			desc.national_number.as_ref().unwrap();
82			desc.national_number.as_ref().unwrap();
83
84			Ok(super::Descriptor {
85				national_number: desc.national_number.ok_or_else(||
86					error::LoadMetadata::from(error::Metadata::MissingValue {
87						phase: "descriptor".into(),
88						name:  "national_number".into(),
89					})).and_then(&regex)?,
90
91				possible_length: desc.possible_length,
92				possible_local_length: desc.possible_local_length,
93				example: desc.example,
94			})
95		};
96
97		let format = |format: loader::Format| -> Result<super::Format, error::LoadMetadata> {
98			Ok(super::Format {
99				pattern: format.pattern.ok_or_else(||
100					error::LoadMetadata::from(error::Metadata::MissingValue {
101						phase: "format".into(),
102						name:  "pattern".into(),
103					})).and_then(&regex)?,
104
105				format: format.format.ok_or_else(||
106					error::LoadMetadata::from(error::Metadata::MissingValue {
107						phase: "format".into(),
108						name:  "format".into()
109					}))?,
110
111				leading_digits: format.leading_digits.into_iter()
112					.map(&regex).collect::<Result<_, _>>()?,
113
114				national_prefix:          format.national_prefix_formatting_rule,
115				national_prefix_optional: format.national_prefix_optional_when_formatting,
116
117				domestic_carrier: format.domestic_carrier,
118			})
119		};
120
121		let metadata = |meta: loader::Metadata| -> Result<super::Metadata, error::LoadMetadata> {
122			Ok(super::Metadata {
123				descriptors: super::Descriptors {
124					general: descriptor(meta.general.ok_or_else(||
125						error::LoadMetadata::from(error::Metadata::MissingValue {
126							phase: "metadata".into(),
127							name:  "generalDesc".into(),
128						}))?)?,
129
130					fixed_line:       tranpose(meta.fixed_line.map(&descriptor))?,
131					mobile:           tranpose(meta.mobile.map(&descriptor))?,
132					toll_free:        tranpose(meta.toll_free.map(&descriptor))?,
133					premium_rate:     tranpose(meta.premium_rate.map(&descriptor))?,
134					shared_cost:      tranpose(meta.shared_cost.map(&descriptor))?,
135					personal_number:  tranpose(meta.personal_number.map(&descriptor))?,
136					voip:             tranpose(meta.voip.map(&descriptor))?,
137					pager:            tranpose(meta.pager.map(&descriptor))?,
138					uan:              tranpose(meta.uan.map(&descriptor))?,
139					emergency:        tranpose(meta.emergency.map(&descriptor))?,
140					voicemail:        tranpose(meta.voicemail.map(&descriptor))?,
141					short_code:       tranpose(meta.short_code.map(&descriptor))?,
142					standard_rate:    tranpose(meta.standard_rate.map(&descriptor))?,
143					carrier:          tranpose(meta.carrier.map(&descriptor))?,
144					no_international: tranpose(meta.no_international.map(&descriptor))?,
145				},
146
147				id: meta.id.ok_or_else(||
148					error::LoadMetadata::from(error::Metadata::MissingValue {
149						phase: "metadata".into(),
150						name:  "id".into()
151					}))?,
152
153				country_code: meta.country_code.ok_or_else(||
154					error::LoadMetadata::from(error::Metadata::MissingValue {
155						phase: "metadata".into(),
156						name: "countryCode".into(),
157					}))?,
158
159				international_prefix: tranpose(meta.international_prefix.map(&regex))?,
160				preferred_international_prefix: meta.preferred_international_prefix,
161				national_prefix: meta.national_prefix,
162				preferred_extension_prefix: meta.preferred_extension_prefix,
163				national_prefix_for_parsing: tranpose(meta.national_prefix_for_parsing.map(&regex))?,
164				national_prefix_transform_rule: meta.national_prefix_transform_rule,
165
166				formats: meta.formats.into_iter().map(&format).collect::<Result<_, _>>()?,
167				international_formats: meta.international_formats.into_iter().map(&format).collect::<Result<_, _>>()?,
168
169				main_country_for_code: meta.main_country_for_code,
170				leading_digits: tranpose(meta.leading_digits.map(&regex))?,
171				mobile_number_portable: meta.mobile_number_portable,
172			})
173		};
174
175		let mut by_id   = FnvHashMap::default();
176		let mut by_code = FnvHashMap::default();
177		let mut regions = FnvHashMap::default();
178
179		for meta in meta {
180			let meta = Arc::new(metadata(meta)?);
181
182			by_id.insert(meta.id.clone(), meta.clone());
183
184			let by_code = by_code.entry(meta.country_code)
185				.or_insert_with(Vec::new);
186
187			let regions = regions.entry(meta.country_code)
188				.or_insert_with(Vec::new);
189
190			if meta.main_country_for_code {
191				by_code.insert(0, meta.clone());
192				regions.insert(0, meta.id.clone())
193			}
194			else {
195				by_code.push(meta.clone());
196				regions.push(meta.id.clone());
197			}
198		}
199
200		Ok(Database {
201			cache:   cache.clone(),
202			by_id:   by_id,
203			by_code: by_code,
204			regions: regions,
205		})
206	}
207
208	/// Get the regular expression cache.
209	pub fn cache(&self) -> Arc<Mutex<RegexCache>> {
210		self.cache.clone()
211	}
212
213	/// Get a metadata entry by country ID.
214	pub fn by_id<Q>(&self, key: &Q) -> Option<&super::Metadata>
215		where Q:      ?Sized + Hash + Eq,
216		      String: Borrow<Q>,
217	{
218		self.by_id.get(key).map(AsRef::as_ref)
219	}
220
221	/// Get metadata entries by country code.
222	pub fn by_code<Q>(&self, key: &Q) -> Option<Vec<&super::Metadata>>
223		where Q:   ?Sized + Hash + Eq,
224		      u16: Borrow<Q>,
225	{
226		self.by_code.get(key).map(|m| m.iter().map(AsRef::as_ref).collect())
227	}
228
229	/// Get all country IDs corresponding to the given country code.
230	pub fn region<Q>(&self, code: &Q) -> Option<Vec<&str>>
231		where Q:   ?Sized + Hash + Eq,
232		      u16: Borrow<Q>
233	{
234		self.regions.get(code).map(|m| m.iter().map(AsRef::as_ref).collect())
235	}
236}