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}