phonenumber_fixed/
phone_number.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::fmt;
16use std::str::FromStr;
17use std::ops::Deref;
18use either::*;
19
20use crate::country;
21use crate::national_number::NationalNumber;
22use crate::extension::Extension;
23use crate::carrier::Carrier;
24use crate::metadata::{DATABASE, Database, Metadata};
25use crate::parser;
26use crate::formatter;
27use crate::validator;
28use crate::error;
29
30/// A phone number.
31#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
32pub struct PhoneNumber {
33	/// The country calling code for this number, as defined by the International
34	/// Telecommunication Union (ITU). For example, this would be 1 for NANPA
35	/// countries, and 33 for France.
36	pub(crate) code: country::Code,
37
38	/// The National (significant) Number, as defined in International
39	/// Telecommunication Union (ITU) Recommendation E.164, without any leading
40	/// zero. The leading-zero is stored separately if required, since this is an
41	/// uint64 and hence cannot store such information. Do not use this field
42	/// directly: if you want the national significant number, call the
43	/// getNationalSignificantNumber method of PhoneNumberUtil.
44	///
45	/// For countries which have the concept of an "area code" or "national
46	/// destination code", this is included in the National (significant) Number.
47	/// Although the ITU says the maximum length should be 15, we have found
48	/// longer numbers in some countries e.g. Germany.  Note that the National
49	/// (significant) Number does not contain the National (trunk) prefix.
50	/// Obviously, as a uint64, it will never contain any formatting (hyphens,
51	/// spaces, parentheses), nor any alphanumeric spellings.
52	pub(crate) national: NationalNumber,
53
54	/// Extension is not standardized in ITU recommendations, except for being
55	/// defined as a series of numbers with a maximum length of 40 digits. It is
56	/// defined as a string here to accommodate for the possible use of a leading
57	/// zero in the extension (organizations have complete freedom to do so, as
58	/// there is no standard defined). Other than digits, some other dialling
59	/// characters such as "," (indicating a wait) may be stored here.
60	pub(crate) extension: Option<Extension>,
61
62	/// The carrier selection code that is preferred when calling this phone
63	/// number domestically. This also includes codes that need to be dialed in
64	/// some countries when calling from landlines to mobiles or vice versa. For
65	/// example, in Columbia, a "3" needs to be dialed before the phone number
66	/// itself when calling from a mobile phone to a domestic landline phone and
67	/// vice versa.
68	///
69	/// Note this is the "preferred" code, which means other codes may work as
70	/// well.
71	pub(crate) carrier: Option<Carrier>,
72}
73
74/// Wrapper to make it easier to access information about the country of a
75/// phone number.
76pub struct Country<'a>(&'a PhoneNumber);
77
78/// The phone number type.
79#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
80#[serde(rename_all = "snake_case")]
81pub enum Type {
82	///
83	FixedLine,
84
85	///
86	Mobile,
87
88	/// In some regions (e.g. the USA), it is impossible to distinguish between
89	/// fixed-line and mobile numbers by looking at the phone number itself.
90	FixedLineOrMobile,
91
92	/// Freephone lines.
93	TollFree,
94
95	///
96	PremiumRate,
97
98	/// The cost of this call is shared between the caller and the recipient, and
99	/// is hence typically less than PREMIUM_RATE calls. See
100	/// http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
101	SharedCost,
102
103	/// A personal number is associated with a particular person, and may be
104	/// routed to either a MOBILE or FIXED_LINE number. Some more information can
105	/// be found here: http://en.wikipedia.org/wiki/Personal_Numbers
106	PersonalNumber,
107
108	/// Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
109	Voip,
110
111	///
112	Pager,
113
114	/// Used for "Universal Access Numbers" or "Company Numbers". They may be
115	/// further routed to specific offices, but allow one number to be used for a
116	/// company.
117	Uan,
118
119	///
120	Emergency,
121
122	/// Used for "Voice Mail Access Numbers".
123	Voicemail,
124
125	///
126	ShortCode,
127
128	///
129	StandardRate,
130
131	///
132	Carrier,
133
134	///
135	NoInternational,
136
137	/// A phone number is of type UNKNOWN when it does not fit any of the known
138	/// patterns for a specific region.
139	Unknown,
140}
141
142impl FromStr for PhoneNumber {
143	type Err = error::Parse;
144
145	fn from_str(s: &str) -> Result<Self, Self::Err> {
146		parser::parse(None, s)
147	}
148}
149
150impl fmt::Display for PhoneNumber {
151	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152		write!(f, "{}", self.format())
153	}
154}
155
156impl PhoneNumber {
157	/// Get information about the country for the phone number.
158	pub fn country(&self) -> Country {
159		Country(self)
160	}
161
162	/// Get the country code.
163	pub fn code(&self) -> &country::Code {
164		&self.code
165	}
166
167	/// Get the national number.
168	pub fn national(&self) -> &NationalNumber {
169		&self.national
170	}
171
172	/// Get the extension.
173	pub fn extension(&self) -> Option<&Extension> {
174		self.extension.as_ref()
175	}
176
177	/// Get the carrier.
178	pub fn carrier(&self) -> Option<&Carrier> {
179		self.carrier.as_ref()
180	}
181
182	/// Prepare a formatter for this `PhoneNumber`.
183	///
184	/// # Example
185	///
186	/// ```
187	/// use phonenumber::{self, country, Mode};
188	///
189	/// let number = phonenumber::parse(Some(country::DE), "301/23456").unwrap()
190	/// 	.format().mode(Mode::National).to_string();
191	///
192	/// assert_eq!("030 123456", number);
193	/// ```
194	pub fn format<'n>(&'n self) -> formatter::Formatter<'n, 'static, 'static> {
195		formatter::format(self)
196	}
197
198	/// Prepare a formatter for this `PhoneNumber` with the given `Database`.
199	pub fn format_with<'n, 'd>(&'n self, database: &'d Database) -> formatter::Formatter<'n, 'd, 'static> {
200		formatter::format_with(database, self)
201	}
202
203	/// Get the metadata that applies to this phone number from the given
204	/// database.
205	pub fn metadata<'a>(&self, database: &'a Database) -> Option<&'a Metadata> {
206		match try_opt!(None; validator::source_for(database, self.code.value(), &self.national.to_string())) {
207			Left(region) =>
208				database.by_id(region.as_ref()),
209
210			Right(code) =>
211				database.by_code(&code).and_then(|m| m.into_iter().next()),
212		}
213	}
214
215	/// Check if the phone number is valid.
216	pub fn is_valid(&self) -> bool {
217		validator::is_valid(self)
218	}
219
220	/// Check if the phone number is valid with the given `Database`.
221	pub fn is_valid_with(&self, database: &Database) -> bool {
222		validator::is_valid_with(database, self)
223	}
224}
225
226impl<'a> Country<'a> {
227	pub fn code(&self) -> u16 {
228		self.0.code.value()
229	}
230
231	pub fn id(&self) -> Option<country::Id> {
232		self.0.metadata(&*DATABASE).map(|m| m.id().parse().unwrap())
233	}
234}
235
236impl<'a> Deref for Country<'a> {
237	type Target = country::Code;
238
239	fn deref(&self) -> &Self::Target {
240		self.0.code()
241	}
242}
243
244#[cfg(test)]
245mod test {
246	use crate::parser;
247	use crate::country;
248
249	#[test]
250	fn country_id() {
251		assert_eq!(country::AU,
252			parser::parse(None, "+61406823897").unwrap()
253				.country().id().unwrap());
254
255		assert_eq!(country::ES,
256			parser::parse(None, "+34666777888").unwrap()
257				.country().id().unwrap());
258
259		assert_eq!(country::KY,
260			parser::parse(None, "+13459492311").unwrap()
261				.country().id().unwrap());
262
263		assert_eq!(country::CA,
264			parser::parse(None, "+16137827274").unwrap()
265				.country().id().unwrap());
266	}
267}