git.iko.soy/typeable/libphonenumber
on 831cd18 help sign in
13 files changed+120−610
since splitsnapshots
unifiedsplit
.github/workflows/ci.yaml−102 LICENSE−21 cxxbits/c_phonenumber.cpp+4−6 cxxbits/c_phonenumberutil.cpp+26−45 include/c_phonenumber.h+8−4 include/c_phonenumberutil.h+20−20 include/common.h+2−3 libphonenumber.cabal+36−81 src/Data/PhoneNumber/Internal/Number.chs+1−1 src/Data/PhoneNumber/Number.hs+10−69 src/Data/PhoneNumber/Util.hs+7−7 test/Leak.hs+6−6 test/Spec.hs−245
.github/workflows/ci.yamldeleted−102
@@ -1,102 +0,0 @@
1−name: CI
2−
3−on:
4− push:
5− branches:
6− - "*"
7− pull_request:
8− branches:
9− - "*"
10− release:
11− types:
12− - prereleased
13−
14−jobs:
15− build:
16− strategy:
17− matrix:
18− platform:
19− - ubuntu-latest
20− ghc_version:
21− - "8.6.5"
22− - "8.8.4"
23− - "8.10.7"
24− - "9.0.2"
25− - "9.2.8"
26− - "9.4.8"
27− - "9.6.7"
28− - "9.8.4"
29− - "9.10.3"
30− - "9.12.2"
31− - "9.14.1"
32− fail-fast: false
33− name: Build on Linux, GHC ${{ matrix.ghc_version }}
34− runs-on: ${{ matrix.platform }}
35− steps:
36− - uses: actions/checkout@v4
37− - uses: haskell-actions/setup@v2
38− with:
39− ghc-version: ${{ matrix.ghc_version }}
40− cabal-version: "3.10.1.0"
41− - name: Install C++ library
42− run: |
43− sudo apt-get update
44− sudo apt-get install -y libphonenumber-dev
45−
46− - name: cabal sdist
47− run: cabal sdist --output-dir "$GITHUB_WORKSPACE/sdist"
48− - name: unpack
49− run: |
50− mkdir -p "$GITHUB_WORKSPACE/unpacked"
51− find "$GITHUB_WORKSPACE/sdist" -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C "$GITHUB_WORKSPACE/unpacked" -xzvf {} \;
52− echo "PKGDIR_libphonenumber=$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/libphonenumber-[0-9.]*')" >> "$GITHUB_ENV"
53− - name: cabal configure
54− run: cd "$PKGDIR_libphonenumber" && cabal configure --with-ghc=ghc-${{ matrix.ghc_version }}
55− - name: Install dependencies
56− run: cd "$PKGDIR_libphonenumber" && cabal build --dependencies-only --enable-tests --haddock-all
57− - name: cabal build
58− run: cd "$PKGDIR_libphonenumber" && cabal build --ghc-options=-Werror
59− - name: cabal test spec_test
60− run: cd "$PKGDIR_libphonenumber" && cabal test spec_test
61− - name: cabal check
62− run: cd "$PKGDIR_libphonenumber" && cabal check
63− - name: cabal haddock
64− run: cd "$PKGDIR_libphonenumber" && cabal haddock
65−
66− dist:
67− needs: build
68− runs-on: ubuntu-latest
69− name: Build source tarball
70− if: github.event_name == 'release'
71− steps:
72− - uses: actions/checkout@v3
73− - uses: haskell-actions/setup@v2
74− with:
75− cabal-version: "3.10.1.0"
76− - name: Install C++ library
77− run: |
78− sudo apt-get update
79− sudo apt-get install -y libphonenumber-dev
80− - name: cabal sdist
81− run: |
82− cabal sdist --output-dir "$GITHUB_WORKSPACE/sdist"
83− echo "dist=$(find "$GITHUB_WORKSPACE/sdist" -maxdepth 1 -type f -name '*.tar.gz')" >> "$GITHUB_ENV"
84− - name: cabal haddock
85− run: |
86− cabal haddock --builddir "$GITHUB_WORKSPACE/doc" --haddock-for-hackage --enable-doc
87− echo "docs=$(find "$GITHUB_WORKSPACE/doc" -maxdepth 1 -type f -name '*-docs.tar.gz')" >> "$GITHUB_ENV"
88− - uses: actions/upload-artifact@v6
89− with:
90− name: Source tarball
91− path: ${{ env.dist }}
92− - uses: svenstaro/upload-release-action@2.11.3
93− with:
94− repo_token: ${{ secrets.GITHUB_TOKEN }}
95− file: ${{ env.dist }}
96− tag: ${{ github.ref }}
97− - name: Upload tarball to hackage
98− run: |
99− curl -X POST 'https://hackage.haskell.org/packages/candidates/' -H "Authorization: X-ApiKey ${{ secrets.HACKAGE_KEY }}" -F "package=@$dist" -w '%{url_effective}\n'
100− - name: Upload haddocks to hackage
101− run: |
102− curl -X PUT "https://hackage.haskell.org/package/$(basename ${docs%-docs.tar.gz})/candidate/docs" -H "Authorization: X-ApiKey ${{ secrets.HACKAGE_KEY }}" -H 'Content-type: application/x-tar' -H 'Content-encoding: gzip' --data-binary "@$docs"
LICENSEdeleted−21
@@ -1,21 +0,0 @@
1−MIT License
2−
3−Copyright (c) 2023 Typeable
4−
5−Permission is hereby granted, free of charge, to any person obtaining a copy
6−of this software and associated documentation files (the "Software"), to deal
7−in the Software without restriction, including without limitation the rights
8−to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9−copies of the Software, and to permit persons to whom the Software is
10−furnished to do so, subject to the following conditions:
11−
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
14−
15−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21−SOFTWARE.
cxxbits/c_phonenumber.cpp+4−6
@@ -55,7 +55,7 @@ static country_code_source unmarshal_country_code_source(PhoneNumber::CountryCod
5555 return static_cast<country_code_source>(value);
5656}
5757
58−extern "C" CxxPhoneNumber *c_phone_number_marshal(phone_number const *c_number)
58+extern "C" PhoneNumber *c_phone_number_marshal(phone_number const *c_number)
5959{
6060 PhoneNumber *number = new PhoneNumber();
6161 if (c_number->extension != nullptr)
@@ -72,12 +72,11 @@ extern "C" CxxPhoneNumber *c_phone_number_marshal(phone_number const *c_number)
7272 number->set_country_code_source(marshal_country_code_source(c_number->country_code_source));
7373 if (c_number->has_number_of_leading_zeros)
7474 number->set_number_of_leading_zeros(c_number->number_of_leading_zeros);
75− return reinterpret_cast<CxxPhoneNumber *>(number);
75+ return number;
7676}
7777
78−extern "C" void c_phone_number_unmarshal(CxxPhoneNumber const *ptr, phone_number *c_number)
78+extern "C" void c_phone_number_unmarshal(PhoneNumber const *number, phone_number *c_number)
7979{
80− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
8180 if (number->has_extension())
8281 unmarshal_string_size(number->extension(), c_number->extension, c_number->extension_size);
8382 else
@@ -100,8 +99,7 @@ extern "C" void c_phone_number_unmarshal(CxxPhoneNumber const *ptr, phone_number
10099 c_number->number_of_leading_zeros = number->number_of_leading_zeros();
101100}
102101
103−extern "C" void c_phone_number_free(CxxPhoneNumber *ptr)
102+extern "C" void c_phone_number_free(PhoneNumber *number)
104103{
105− auto number = reinterpret_cast<PhoneNumber *>(ptr);
106104 delete number;
107105}
cxxbits/c_phonenumberutil.cpp+26−45
@@ -310,11 +310,10 @@ extern "C" void c_phone_number_util_normalize_dialable_chars_only(
310310}
311311
312312extern "C" void c_phone_number_util_get_national_significant_number(
313− CxxPhoneNumber const *ptr,
313+ PhoneNumber const *number,
314314 c_string *c_nsn
315315)
316316{
317− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
318317 std::string nsn;
319318 PhoneNumberUtil::GetInstance()->GetNationalSignificantNumber(*number, &nsn);
320319 unmarshal_c_string(nsn, *c_nsn);
@@ -331,25 +330,23 @@ extern "C" void c_phone_number_util_get_country_mobile_token(
331330}
332331
333332extern "C" void c_phone_number_util_format(
334− CxxPhoneNumber const *ptr,
333+ PhoneNumber const *number,
335334 phone_number_format format,
336335 c_string *c_string
337336)
338337{
339− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
340338 std::string string;
341339 PhoneNumberUtil::GetInstance()->Format(*number, marshal_phone_number_format(format), &string);
342340 unmarshal_c_string(string, *c_string);
343341}
344342
345343extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
346− CxxPhoneNumber const *ptr,
344+ PhoneNumber const *number,
347345 char const *c_carrier_code,
348346 size_t c_carrier_code_size,
349347 c_string *c_string
350348)
351349{
352− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
353350 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
354351 std::string string;
355352 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithCarrierCode(*number, carrier_code, &string);
@@ -357,13 +354,12 @@ extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
357354}
358355
359356extern "C" void c_phone_number_util_format_national_number_with_preferred_carrier_code(
360− CxxPhoneNumber const *ptr,
357+ PhoneNumber const *number,
361358 char const *c_carrier_code,
362359 size_t c_carrier_code_size,
363360 c_string *c_string
364361)
365362{
366− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
367363 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
368364 std::string string;
369365 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithPreferredCarrierCode(*number, carrier_code, &string);
@@ -371,14 +367,13 @@ extern "C" void c_phone_number_util_format_national_number_with_preferred_carrie
371367}
372368
373369extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
374− CxxPhoneNumber const *ptr,
370+ PhoneNumber const *number,
375371 char const *c_region,
376372 size_t c_region_size,
377373 int with_formatting,
378374 c_string *c_string
379375)
380376{
381− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
382377 std::string const region(c_region, c_region_size);
383378 std::string string;
384379 PhoneNumberUtil::GetInstance()->FormatNumberForMobileDialing(*number, region, with_formatting, &string);
@@ -386,13 +381,12 @@ extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
386381}
387382
388383extern "C" void c_phone_number_util_format_out_of_country_calling_number(
389− CxxPhoneNumber const *ptr,
384+ PhoneNumber const *number,
390385 char const *c_region,
391386 size_t c_region_size,
392387 c_string *c_string
393388)
394389{
395− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
396390 std::string const region(c_region, c_region_size);
397391 std::string string;
398392 PhoneNumberUtil::GetInstance()->FormatOutOfCountryCallingNumber(*number, region, &string);
@@ -400,13 +394,12 @@ extern "C" void c_phone_number_util_format_out_of_country_calling_number(
400394}
401395
402396extern "C" void c_phone_number_util_format_in_original_format(
403− CxxPhoneNumber const *ptr,
397+ PhoneNumber const *number,
404398 char const *c_region,
405399 size_t c_region_size,
406400 c_string *c_string
407401)
408402{
409− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
410403 std::string const region(c_region, c_region_size);
411404 std::string string;
412405 PhoneNumberUtil::GetInstance()->FormatInOriginalFormat(*number, region, &string);
@@ -414,26 +407,24 @@ extern "C" void c_phone_number_util_format_in_original_format(
414407}
415408
416409extern "C" void c_phone_number_util_format_out_of_country_keeping_alpha_chars(
417− CxxPhoneNumber const *ptr,
410+ PhoneNumber const *number,
418411 char const *c_region,
419412 size_t c_region_size,
420413 c_string *c_string
421414)
422415{
423− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
424416 std::string const region(c_region, c_region_size);
425417 std::string string;
426418 PhoneNumberUtil::GetInstance()->FormatOutOfCountryKeepingAlphaChars(*number, region, &string);
427419 unmarshal_c_string(string, *c_string);
428420}
429421
430−extern "C" CxxPhoneNumber *c_phone_number_util_truncate_too_long_number(CxxPhoneNumber const *ptr)
422+extern "C" PhoneNumber *c_phone_number_util_truncate_too_long_number(PhoneNumber const *input)
431423{
432− auto input = reinterpret_cast<PhoneNumber const *>(ptr);
433424 auto *output = new PhoneNumber(*input);
434425 if (PhoneNumberUtil::GetInstance()->TruncateTooLongNumber(output))
435426 {
436− return reinterpret_cast<CxxPhoneNumber *>(output);
427+ return output;
437428 }
438429 else
439430 {
@@ -442,37 +433,33 @@ extern "C" CxxPhoneNumber *c_phone_number_util_truncate_too_long_number(CxxPhone
442433 }
443434}
444435
445−extern "C" phone_number_type c_phone_number_util_get_number_type(CxxPhoneNumber const *ptr)
436+extern "C" phone_number_type c_phone_number_util_get_number_type(PhoneNumber const *number)
446437{
447− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
448438 return unmarshal_phone_number_type(
449439 PhoneNumberUtil::GetInstance()->GetNumberType(*number)
450440 );
451441}
452442
453−extern "C" int c_phone_number_util_is_valid_number(CxxPhoneNumber const *ptr)
443+extern "C" int c_phone_number_util_is_valid_number(PhoneNumber const *number)
454444{
455− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
456445 return PhoneNumberUtil::GetInstance()->IsValidNumber(*number);
457446}
458447
459448extern "C" int c_phone_number_util_is_valid_number_for_region(
460− CxxPhoneNumber const *ptr,
449+ PhoneNumber const *number,
461450 char const *c_region,
462451 size_t c_region_size
463452)
464453{
465− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
466454 std::string const region(c_region, c_region_size);
467455 return PhoneNumberUtil::GetInstance()->IsValidNumberForRegion(*number, region);
468456}
469457
470458extern "C" void c_phone_number_util_get_region_code_for_number(
471− CxxPhoneNumber const *ptr,
459+ PhoneNumber const *number,
472460 c_string *c_region
473461)
474462{
475− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
476463 std::string region;
477464 PhoneNumberUtil::GetInstance()->GetRegionCodeForNumber(*number, &region);
478465 unmarshal_c_string(region, *c_region);
@@ -531,11 +518,10 @@ extern "C" void c_phone_number_util_get_ndd_prefix_for_region(
531518}
532519
533520extern "C" validation_result c_phone_number_util_is_possible_number_for_type_with_reason(
534− CxxPhoneNumber const *ptr,
521+ PhoneNumber const *number,
535522 phone_number_type ntype
536523)
537524{
538− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
539525 return unmarshal_validation_result(
540526 PhoneNumberUtil::GetInstance()->IsPossibleNumberForTypeWithReason(
541527 *number,
@@ -544,15 +530,13 @@ extern "C" validation_result c_phone_number_util_is_possible_number_for_type_wit
544530 );
545531}
546532
547−extern "C" int c_phone_number_util_can_be_internationally_dialed(CxxPhoneNumber const *ptr)
533+extern "C" int c_phone_number_util_can_be_internationally_dialed(PhoneNumber const *number)
548534{
549− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
550535 return PhoneNumberUtil::GetInstance()->CanBeInternationallyDialled(*number);
551536}
552537
553−extern "C" int c_phone_number_util_is_number_geographical_1(CxxPhoneNumber const *ptr)
538+extern "C" int c_phone_number_util_is_number_geographical_1(PhoneNumber const *number)
554539{
555− auto number = reinterpret_cast<PhoneNumber const *>(ptr);
556540 return PhoneNumberUtil::GetInstance()->IsNumberGeographical(*number);
557541}
558542
@@ -572,14 +556,14 @@ extern "C" error_type c_phone_number_util_parse(
572556 size_t c_string_size,
573557 char const *c_region,
574558 size_t c_region_size,
575− CxxPhoneNumber **number
559+ PhoneNumber **number
576560)
577561{
578562 std::string const string(c_string, c_string_size);
579563 std::string const region(c_region, c_region_size);
580− *number = reinterpret_cast<CxxPhoneNumber *>(new PhoneNumber());
564+ *number = new PhoneNumber();
581565 return unmarshal_error_type(
582− PhoneNumberUtil::GetInstance()->Parse(string, region, reinterpret_cast<PhoneNumber *>(*number))
566+ PhoneNumberUtil::GetInstance()->Parse(string, region, *number)
583567 );
584568}
585569
@@ -588,24 +572,22 @@ extern "C" error_type c_phone_number_util_parse_and_keep_raw_input(
588572 size_t c_string_size,
589573 char const *c_region,
590574 size_t c_region_size,
591− CxxPhoneNumber **number
575+ PhoneNumber **number
592576)
593577{
594578 std::string const string(c_string, c_string_size);
595579 std::string const region(c_region, c_region_size);
596− *number = reinterpret_cast<CxxPhoneNumber *>(new PhoneNumber());
580+ *number = new PhoneNumber();
597581 return unmarshal_error_type(
598− PhoneNumberUtil::GetInstance()->ParseAndKeepRawInput(string, region, reinterpret_cast<PhoneNumber *>(*number))
582+ PhoneNumberUtil::GetInstance()->ParseAndKeepRawInput(string, region, *number)
599583 );
600584}
601585
602586extern "C" match_type c_phone_number_util_is_number_match(
603− CxxPhoneNumber const *ptr1,
604− CxxPhoneNumber const *ptr2
587+ PhoneNumber const *number1,
588+ PhoneNumber const *number2
605589)
606590{
607− auto number1 = reinterpret_cast<PhoneNumber const *>(ptr1);
608− auto number2 = reinterpret_cast<PhoneNumber const *>(ptr2);
609591 return unmarshal_match_type(
610592 PhoneNumberUtil::GetInstance()->IsNumberMatch(*number1, *number2)
611593 );
@@ -626,12 +608,11 @@ extern "C" match_type c_phone_number_util_is_number_match_with_two_strings(
626608}
627609
628610extern "C" match_type c_phone_number_util_is_number_match_with_one_string(
629− CxxPhoneNumber const *ptr1,
611+ PhoneNumber const *number1,
630612 char const *c_number2,
631613 size_t c_number2_size
632614)
633615{
634− auto number1 = reinterpret_cast<PhoneNumber const *>(ptr1);
635616 std::string const number2(c_number2, c_number2_size);
636617 return unmarshal_match_type(
637618 PhoneNumberUtil::GetInstance()->IsNumberMatchWithOneString(*number1, number2)
include/c_phonenumber.h+8−4
@@ -43,16 +43,20 @@ typedef struct
4343 char has_number_of_leading_zeros;
4444} phone_number;
4545
46−struct CxxPhoneNumber;
46+#ifdef __cplusplus
47+typedef i18n::phonenumbers::PhoneNumber PhoneNumber;
48+#else
49+typedef struct PhoneNumber PhoneNumber;
50+#endif
4751
4852// The returned object is allocated by `new` and managed by C++ RAII, and it is
4953// haskell's responsibility to call its finalizer (c_phone_number_free).
50−struct CxxPhoneNumber *c_phone_number_marshal(phone_number const *);
54+PhoneNumber *c_phone_number_marshal(phone_number const *);
5155
5256// phone_number * points to an area which will be filled with the data of the
5357// given PhoneNumber.
54−void c_phone_number_unmarshal(struct CxxPhoneNumber const *, phone_number *);
58+void c_phone_number_unmarshal(PhoneNumber const *, phone_number *);
5559
56−void c_phone_number_free(struct CxxPhoneNumber *);
60+void c_phone_number_free(PhoneNumber *);
5761
5862#endif
include/c_phonenumberutil.h+20−20
@@ -97,34 +97,34 @@ int c_phone_number_util_is_alpha_number(char const *, size_t);
9797void c_phone_number_util_convert_alpha_characters_in_number(char const *, size_t, c_string *);
9898void c_phone_number_util_normalize_digits_only(char const *, size_t, c_string *);
9999void c_phone_number_util_normalize_dialable_chars_only(char const *, size_t, c_string *);
100−void c_phone_number_util_get_national_significant_number(struct CxxPhoneNumber const *, c_string *);
100+void c_phone_number_util_get_national_significant_number(PhoneNumber const *, c_string *);
101101void c_phone_number_util_get_country_mobile_token(int, c_string *);
102−void c_phone_number_util_format(struct CxxPhoneNumber const *, enum phone_number_format, c_string *);
103−void c_phone_number_util_format_national_number_with_carrier_code(struct CxxPhoneNumber const *, char const *, size_t, c_string *);
104−void c_phone_number_util_format_national_number_with_preferred_carrier_code(struct CxxPhoneNumber const *, char const *, size_t, c_string *);
105−void c_phone_number_util_format_number_for_mobile_dialing(struct CxxPhoneNumber const *, char const *, size_t, int, c_string *);
106−void c_phone_number_util_format_out_of_country_calling_number(struct CxxPhoneNumber const *, char const *, size_t, c_string *);
107−void c_phone_number_util_format_in_original_format(struct CxxPhoneNumber const *, char const *, size_t, c_string *);
108−void c_phone_number_util_format_out_of_country_keeping_alpha_chars(struct CxxPhoneNumber const *, char const *, size_t, c_string *);
102+void c_phone_number_util_format(PhoneNumber const *, enum phone_number_format, c_string *);
103+void c_phone_number_util_format_national_number_with_carrier_code(PhoneNumber const *, char const *, size_t, c_string *);
104+void c_phone_number_util_format_national_number_with_preferred_carrier_code(PhoneNumber const *, char const *, size_t, c_string *);
105+void c_phone_number_util_format_number_for_mobile_dialing(PhoneNumber const *, char const *, size_t, int, c_string *);
106+void c_phone_number_util_format_out_of_country_calling_number(PhoneNumber const *, char const *, size_t, c_string *);
107+void c_phone_number_util_format_in_original_format(PhoneNumber const *, char const *, size_t, c_string *);
108+void c_phone_number_util_format_out_of_country_keeping_alpha_chars(PhoneNumber const *, char const *, size_t, c_string *);
109109// /!\ May return NULL
110−struct CxxPhoneNumber *c_phone_number_util_truncate_too_long_number(struct CxxPhoneNumber const *);
111−enum phone_number_type c_phone_number_util_get_number_type(struct CxxPhoneNumber const *);
112−int c_phone_number_util_is_valid_number(struct CxxPhoneNumber const *);
113−int c_phone_number_util_is_valid_number_for_region(struct CxxPhoneNumber const *, char const *, size_t);
114−void c_phone_number_util_get_region_code_for_number(struct CxxPhoneNumber const *, c_string *);
110+PhoneNumber *c_phone_number_util_truncate_too_long_number(PhoneNumber const *);
111+enum phone_number_type c_phone_number_util_get_number_type(PhoneNumber const *);
112+int c_phone_number_util_is_valid_number(PhoneNumber const *);
113+int c_phone_number_util_is_valid_number_for_region(PhoneNumber const *, char const *, size_t);
114+void c_phone_number_util_get_region_code_for_number(PhoneNumber const *, c_string *);
115115int c_phone_number_util_get_country_code_for_region(char const *, size_t);
116116void c_phone_number_util_get_region_code_for_country_code(int, c_string *);
117117void c_phone_number_util_get_region_codes_for_country_calling_code(int, c_string **, size_t *);
118118int c_phone_number_util_is_nanpa_country(char const *, size_t);
119119void c_phone_number_util_get_ndd_prefix_for_region(char const *, size_t, int, c_string *);
120−enum validation_result c_phone_number_util_is_possible_number_for_type_with_reason(struct CxxPhoneNumber const *, enum phone_number_type);
121−int c_phone_number_util_can_be_internationally_dialed(struct CxxPhoneNumber const *);
122−int c_phone_number_util_is_number_geographical_1(struct CxxPhoneNumber const *);
120+enum validation_result c_phone_number_util_is_possible_number_for_type_with_reason(PhoneNumber const *, enum phone_number_type);
121+int c_phone_number_util_can_be_internationally_dialed(PhoneNumber const *);
122+int c_phone_number_util_is_number_geographical_1(PhoneNumber const *);
123123int c_phone_number_util_is_number_geographical_2(enum phone_number_type, int);
124−enum error_type c_phone_number_util_parse(char const *, size_t, char const *, size_t, struct CxxPhoneNumber **);
125−enum error_type c_phone_number_util_parse_and_keep_raw_input(char const *, size_t, char const *, size_t, struct CxxPhoneNumber **);
126−enum match_type c_phone_number_util_is_number_match(struct CxxPhoneNumber const *, struct CxxPhoneNumber const *);
124+enum error_type c_phone_number_util_parse(char const *, size_t, char const *, size_t, PhoneNumber **);
125+enum error_type c_phone_number_util_parse_and_keep_raw_input(char const *, size_t, char const *, size_t, PhoneNumber **);
126+enum match_type c_phone_number_util_is_number_match(PhoneNumber const *, PhoneNumber const *);
127127enum match_type c_phone_number_util_is_number_match_with_two_strings(char const *, size_t, char const *, size_t);
128−enum match_type c_phone_number_util_is_number_match_with_one_string(struct CxxPhoneNumber const *, char const *, size_t);
128+enum match_type c_phone_number_util_is_number_match_with_one_string(PhoneNumber const *, char const *, size_t);
129129
130130#endif
include/common.h+2−3
@@ -4,7 +4,6 @@
44#include <cstddef>
55#include <cstring>
66#include <type_traits>
7−#include <utility>
87
98// Given `enum T { A, B, C }` and `enum S { X, Y, Z }`, we can use
109// `is_same_enum<enum_values<T, A, B, C>, enum_values<S, X, Y, Z>>::value`
@@ -32,7 +31,7 @@ struct is_same_enum: std::false_type
3231
3332template<typename T, T... TVals, typename S, S... SVals>
3433struct is_same_enum<enum_values<T, TVals...>, enum_values<S, SVals...>>:
35− std::integral_constant<bool, std::is_same<
34+ std::integral_constant<bool, std::is_same_v<
3635 std::integer_sequence<
3736 typename std::common_type<
3837 typename std::underlying_type<T>::type,
@@ -47,7 +46,7 @@ struct is_same_enum<enum_values<T, TVals...>, enum_values<S, SVals...>>:
4746 >::type,
4847 SVals...
4948 >
50− >::value>
49+ >>
5150{};
5251
5352inline void unmarshal_string_size(std::string const &string, char *&c_string, size_t &c_string_size)
libphonenumber.cabal+36−81
@@ -1,6 +1,6 @@
11cabal-version: 3.0
22name: libphonenumber
3−version: 0.1.4.0
3+version: 0.0.0.0
44category: Data
55synopsis: Parsing, formatting, and validating international phone
66 numbers
@@ -8,8 +8,7 @@ description:
88 This package provides bindings for the C++ version of the
99 <https://github.com/google/libphonenumber libphonenumber library>.
1010 The bindings currently do not include @AsYouTypeFormatter@
11− and @ShortNumberInfo@. The C++ library must be of version
12− >= 8.7.0.
11+ and @ShortNumberInfo@.
1312
1413 The interface largely resembles that of the original unified
1514 C++, Java, and JavaScript version of the library, with some
@@ -20,66 +19,37 @@ description:
2019 else has installed a global logger which could observe
2120 side-effects from library calls.
2221
23− The underlying library internally uses UTF-8 encoded byte
24− strings. To avoid decoding overhead where it is unnecessary,
25− and to avoid a dependency on @text@, we use 'ByteString'
26− throughout the library instead of 'Data.Text.Text'.
27−
28−copyright: 2023-2025 Typeable
29−author: Typeable
30−maintainer: mniip@typeable.io
31−homepage: https://github.com/typeable/libphonenumber/
32−license: MIT
33−license-file: LICENSE
34−
35−tested-with:
36− , GHC == 8.6.5
37− , GHC == 8.8.4
38− , GHC == 8.10.7
39− , GHC == 9.0.2
40− , GHC == 9.2.8
41− , GHC == 9.4.8
42− , GHC == 9.6.7
43− , GHC == 9.8.4
44− , GHC == 9.10.3
45− , GHC == 9.12.2
46− , GHC == 9.14.1
47−
48−build-type: Simple
22+build-type: Simple
4923
5024extra-source-files:
51− , include/*.h
52− , test/libphonenumber.supp
53−
54−source-repository head
55− type: git
56− location: https://github.com/typeable/libphonenumber/
25+ include/*.h
26+ test/libphonenumber.supp
5727
5828library
5929 exposed-modules:
60− , Data.PhoneNumber.Number
61− , Data.PhoneNumber.Util
30+ Data.PhoneNumber.Number
31+ Data.PhoneNumber.Util
6232 other-modules:
63− , Data.PhoneNumber.Internal.Common
64− , Data.PhoneNumber.Internal.Number
65− , Data.PhoneNumber.Internal.Util
33+ Data.PhoneNumber.Internal.Common
34+ Data.PhoneNumber.Internal.Number
35+ Data.PhoneNumber.Internal.Util
6636 build-depends:
67− , base >= 4.12 && < 4.23
68− , bytestring >= 0.10.8 && < 0.13
69− , containers >= 0.6.0 && < 0.9
70− , deepseq >= 1.4.4 && < 1.6
71− , transformers >= 0.5.5 && < 0.7
37+ base >= 4.12 && < 4.18
38+ , bytestring
39+ , containers
40+ , deepseq
41+ , transformers
7242 build-tool-depends: c2hs:c2hs
73− pkgconfig-depends: protobuf
7443 include-dirs: include
7544 includes:
76− , c_phonenumber.h
77− , c_phonenumberutil.h
45+ c_phonenumber.h
46+ c_phonenumberutil.h
7847 cxx-sources:
79− , cxxbits/c_phonenumber.cpp
80− , cxxbits/c_phonenumberutil.cpp
48+ cxxbits/c_phonenumber.cpp
49+ cxxbits/c_phonenumberutil.cpp
8150 extra-libraries:
82− , phonenumber
51+ phonenumber
52+ protobuf
8353 if impl(ghc >= 9.4)
8454 build-depends: system-cxx-std-lib
8555 else
@@ -87,43 +57,28 @@ library
8757 hs-source-dirs: src
8858 default-language: Haskell2010
8959 default-extensions:
90− , DeriveAnyClass
91− , DeriveDataTypeable
92− , DeriveGeneric
93− , DerivingStrategies
94− , GeneralizedNewtypeDeriving
95− , LambdaCase
96− , NamedFieldPuns
97− , OverloadedStrings
98− , PatternSynonyms
99− , StandaloneDeriving
100− , RecordWildCards
101− , ViewPatterns
60+ DeriveAnyClass
61+ DeriveDataTypeable
62+ DeriveGeneric
63+ DerivingStrategies
64+ GeneralizedNewtypeDeriving
65+ LambdaCase
66+ NamedFieldPuns
67+ OverloadedStrings
68+ PatternSynonyms
69+ StandaloneDeriving
70+ RecordWildCards
71+ ViewPatterns
10272 if impl(ghc >= 9.2)
10373 default-extensions: NoFieldSelectors
104− ghc-options: -Wall -Wextra
105−
106−test-suite spec_test
107− type: exitcode-stdio-1.0
108− build-depends:
109− , base
110− , bytestring
111− , containers
112− , hspec >= 2.10.8 && < 2.12
113− , libphonenumber
114− , QuickCheck >= 2.13.1 && < 2.16
115− main-is: Spec.hs
116− hs-source-dirs: test
117− default-language: Haskell2010
118− ghc-options: -Wall -Wextra
74+ ghc-options: -Wall -Wextra -Werror
11975
12076test-suite leak_test
12177 type: exitcode-stdio-1.0
12278 build-depends:
123− , base
79+ base
12480 , libphonenumber
125− , process >= 1.6.5 && < 1.7
81+ , process
12682 main-is: Leak.hs
12783 hs-source-dirs: test
12884 default-language: Haskell2010
129− ghc-options: -Wall -Wextra
src/Data/PhoneNumber/Internal/Number.chs+1−1
@@ -126,7 +126,7 @@ acquireCPhoneNumber p = do
126126-- , 'Data.PhoneNumber.Number.numberOfLeadingZeros' :: !('Maybe' 'Int')
127127-- }
128128-- @
129−{#pointer *CxxPhoneNumber as PhoneNumber foreign finalizer c_phone_number_free newtype#}
129+{#pointer *PhoneNumber foreign finalizer c_phone_number_free newtype#}
130130
131131{#fun unsafe c_phone_number_marshal
132132 { withCPhoneNumber* `CPhoneNumber'
src/Data/PhoneNumber/Number.hs+10−69
@@ -21,10 +21,16 @@ module Data.PhoneNumber.Number
2121 ) where
2222
2323import Data.ByteString (ByteString)
24−import Data.PhoneNumber.Internal.Number
25− ( CPhoneNumber(CPhoneNumber), PhoneNumber, CountryCodeSource, toCPhoneNumber
26− , fromCPhoneNumber
27− )
24+import Data.PhoneNumber.Internal.Number hiding
25+ ( pattern PhoneNumber
26+ , extension
27+ , rawInput
28+ , preferredDomesticCarrierCode
29+ , nationalNumber
30+ , countryCode
31+ , italianLeadingZero
32+ , countryCodeSource
33+ , numberOfLeadingZeros )
2834import qualified Data.PhoneNumber.Internal.Number as I
2935
3036-- | A country calling code (International Subscriber Dialing code, ISD code),
@@ -73,68 +79,3 @@ pattern PhoneNumber
7379 = fromCPhoneNumber $ CPhoneNumber{..}
7480
7581{-# COMPLETE PhoneNumber #-}
76−
77−-- | E.g.:
78−--
79−-- @
80−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.Canonicalize' 'Nothing' "+1 800-234-5678 ext. 1234"
81−-- = 'Right' v'PhoneNumber' { 'extension' = 'Just' "1234", .. }
82−-- @
83−extension :: PhoneNumber -> Maybe ByteString
84−
85−-- | E.g.:
86−--
87−-- @
88−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.KeepRawInput' 'Nothing' " + 1(2-3~4*5.6 "
89−-- = 'Right' v'PhoneNumber' { 'rawInput' = 'Just' " + 1(2-3~4*5.6 ", .. }
90−-- @
91−rawInput :: PhoneNumber -> Maybe ByteString
92−
93−-- | E.g.:
94−--
95−-- @
96−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.KeepRawInput' ('Just' \"BR\") "0 41 (21) 2345-6789"
97−-- = 'Right' v'PhoneNumber' { 'preferredDomesticCarrierCode' = 'Just' "41", .. }
98−-- @
99−preferredDomesticCarrierCode :: PhoneNumber -> Maybe ByteString
100−
101−-- | You probably want to use 'Data.PhoneNumber.Util.nationalSignificantNumber'
102−-- instead. E.g.:
103−--
104−-- @
105−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.Canonicalize' 'Nothing' "+800 0001 2345"
106−-- = 'Right' v'PhoneNumber' { 'nationalNumber' = 12345, 'numberOfLeadingZeros' = Just 3, .. }
107−-- @
108−nationalNumber :: PhoneNumber -> Word
109−
110−-- | E.g.:
111−--
112−-- @
113−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.Canonicalize' ('Just' \"US\") "800-234-5678"
114−-- = 'Right' v'PhoneNumber' { 'countryCode' = 1, .. }
115−-- @
116−countryCode :: PhoneNumber -> CountryCode
117−
118−-- | E.g.:
119−--
120−-- @
121−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.Canonicalize' 'Nothing' "+39 06 1234 5678"
122−-- = 'Right' v'PhoneNumber' { 'italianLeadingZero' = 'Just' 'True', .. }
123−-- @
124−italianLeadingZero :: PhoneNumber -> Maybe Bool
125−
126−-- | E.g.:
127−--
128−-- @
129−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.KeepRawInput' ('Just' \"US\") "011 800 1234 5678"
130−-- = 'Right' v'PhoneNumber' { 'countryCodeSource' = 'Just' 'FromNumberWithIdd', .. }
131−-- @
132−countryCodeSource :: PhoneNumber -> Maybe CountryCodeSource
133−
134−-- | E.g.:
135−--
136−-- @
137−-- 'Data.PhoneNumber.Util.parseNumber' 'Data.PhoneNumber.Util.Canonicalize' 'Nothing' "+800 0001 2345"
138−-- = 'Right' v'PhoneNumber' { 'numberOfLeadingZeros' = Just 3, 'nationalNumber' = 12345, .. }
139−-- @
140−numberOfLeadingZeros :: PhoneNumber -> Maybe Int
src/Data/PhoneNumber/Util.hs+7−7
@@ -371,12 +371,12 @@ nddPrefixForRegion strip (Region region) = unsafeDupablePerformIO $ mask_ $
371371-- 3. For some numbers (particularly fixed-line), many regions have the concept
372372-- of area code, which together with subscriber number constitute the National
373373-- Significant Number. It is sometimes okay to dial only the subscriber number
374−-- when dialing in the same area. This function will return
375−-- 'IsPossibleLocalOnly' if the subscriber-number-only version is passed in. On
376−-- the other hand, because 'isValidNumber' validates using information on both
377−-- starting digits (for fixed line numbers, that would most likely be area
378−-- codes) and length (obviously includes the length of area codes for fixed line
379−-- numbers), it will return 'False' for the subscriber-number-only version.
374+-- when dialing in the same area. This function will return IsPossibleLocalOnly
375+-- if the subscriber-number-only version is passed in. On the other hand,
376+-- because 'isValidNumber' validates using information on both starting digits
377+-- (for fixed line numbers, that would most likely be area codes) and length
378+-- (obviously includes the length of area codes for fixed line numbers), it will
379+-- return 'False' for the subscriber-number-only version.
380380possibleNumber :: PhoneNumberType -> PhoneNumber -> ValidationResult
381381possibleNumber ntype pn = unsafeDupablePerformIO $
382382 c_phone_number_util_is_possible_number_for_type_with_reason pn ntype
@@ -445,7 +445,7 @@ data ParseMode
445445-- 'isValidNumber'.
446446--
447447-- Returns an error if the string is not considered to be a viable phone number
448−-- (e.g. too few or too many digits) or if no 'Region' was supplied and the
448+-- (e.g. too few or too many digits) or if 'noRegion' was supplied and the
449449-- number is not in international format (does not start with @\'+\'@).
450450parseNumber
451451 :: ParseMode
test/Leak.hs+6−6
@@ -74,7 +74,7 @@ main = do
7474 carrierCode = "10"
7575 nonGeoCode = 800
7676 phoneString = "+41 44 668 1800"
77− Right phoneNumber = parseNumber KeepRawInput Nothing phoneString
77+ Right phoneNumber = parseNumber KeepRawInput noRegion phoneString
7878 hammer iter (\(PhoneNumber a b c d e f g h) -> PhoneNumber a b c d e f g h) phoneNumber
7979 hammer iter supportedTypesForRegion region
8080 hammer iter supportedTypesForNonGeoEntity nonGeoCode
@@ -96,7 +96,7 @@ main = do
9696 hammer iter (formatNumber (OutOfCountry region False)) phoneNumber
9797 hammer iter truncateTooLongNumber phoneNumber
9898 hammer iter numberType phoneNumber
99− hammer iter (isValidNumber (Just (Right region))) phoneNumber
99+ hammer iter (isValidNumber (Just region)) phoneNumber
100100 hammer iter regionForNumber phoneNumber
101101 hammer iter countryCodeForRegion region
102102 hammer iter regionForCountryCode countryCallingCode
@@ -107,10 +107,10 @@ main = do
107107 hammer iter canBeInternationallyDialed phoneNumber
108108 hammer iter isGeographicalNumber phoneNumber
109109 hammer iter (isGeographicalNumberType FixedLine) countryCallingCode
110− hammer iter (parseNumber Canonicalize (Just region)) phoneString
111− hammer iter (parseNumber Canonicalize (Just region)) ""
112− hammer iter (parseNumber KeepRawInput (Just region)) phoneString
113− hammer iter (parseNumber KeepRawInput (Just region)) ""
110+ hammer iter (parseNumber Canonicalize region) phoneString
111+ hammer iter (parseNumber Canonicalize region) ""
112+ hammer iter (parseNumber KeepRawInput region) phoneString
113+ hammer iter (parseNumber KeepRawInput region) ""
114114 hammer iter (matchNumbers (Left phoneString)) (Left phoneString)
115115 hammer iter (matchNumbers (Left phoneString)) (Right phoneNumber)
116116 hammer iter (matchNumbers (Right phoneNumber)) (Left phoneString)
test/Spec.hsdeleted−245
@@ -1,245 +0,0 @@
1−{-# LANGUAGE DerivingStrategies #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−import Control.Applicative
5−import Control.Monad
6−import qualified Data.ByteString as BS
7−import qualified Data.ByteString.Char8 as BSC
8−import Data.Either
9−import Data.PhoneNumber.Number
10−import Data.PhoneNumber.Util
11−import qualified Data.Set as S
12−import Test.Hspec
13−import Test.Hspec.QuickCheck
14−import Test.QuickCheck
15−
16−newtype CC = CC CountryCode
17− deriving newtype (Show)
18−
19−instance Arbitrary CC where
20− arbitrary = CC . CountryCode <$> choose (-10, 1000)
21− shrink (CC (CountryCode cc)) = CC . CountryCode <$> shrink cc
22−
23−newtype Reg = Reg Region
24− deriving newtype (Show)
25−
26−instance Arbitrary Reg where
27− arbitrary = do
28− c1 <- elements ['A'..'Z']
29− c2 <- elements ['A'..'Z']
30− pure $ Reg $ Region $ BSC.pack [c1, c2]
31−
32−newtype MReg = MReg (Maybe Region)
33− deriving newtype (Show)
34−
35−instance Arbitrary MReg where
36− arbitrary = MReg . fmap (\(Reg r) -> r) <$> arbitrary
37− shrink (MReg (Just _)) = [MReg Nothing]
38− shrink (MReg Nothing) = []
39−
40−newtype ParserInput = ParserInput BS.ByteString
41− deriving newtype (Show)
42−
43−instance Arbitrary ParserInput where
44− arbitrary = do
45− len <- choose (0, 20)
46− xs <- replicateM len $ frequency
47− [ (10, elements "#()+-0123456789")
48− , (1, elements "'*,./:;") ]
49− pure $ ParserInput $ BSC.pack xs
50− shrink (ParserInput bs) = ParserInput . BS.pack <$> shrink (BS.unpack bs)
51−
52−data ParsedNumber = ParsedNumber (ParseMode, Maybe Region, ParserInput) PhoneNumber
53− deriving stock (Show)
54−
55−instance Arbitrary ParsedNumber where
56− arbitrary = do
57− mode <- elements [Canonicalize, KeepRawInput]
58− liftA2 ((,,) mode) arbitrary arbitrary
59− `suchThatMap` \(_, MReg mRegion, ParserInput input) ->
60− case parseNumber mode mRegion input of
61− Right pn -> Just $ ParsedNumber (mode, mRegion, ParserInput input) pn
62− _ -> Nothing
63− shrink (ParsedNumber (mode, region, input) _) = do
64− ParserInput input' <- shrink input
65− case parseNumber mode region input' of
66− Right pn -> pure $ ParsedNumber (mode, region, ParserInput input') pn
67− _ -> empty
68−
69−regZZ, reg001 :: Region
70−regZZ = "ZZ"
71−reg001 = "001"
72−
73−cc0 :: CountryCode
74−cc0 = 0
75−
76−main :: IO ()
77−main = hspec $ modifyMaxSuccess (* 10) $ do
78− describe "supportedRegions" $ do
79− prop "doesn't contain ZZ" $ regZZ `S.notMember` supportedRegions
80− prop "doesn't contain 001" $ reg001 `S.notMember` supportedRegions
81−
82− describe "supportedGlobalNetworkCallingCodes" $ do
83− prop "doesn't contain 0" $ cc0 `S.notMember` supportedGlobalNetworkCallingCodes
84− prop "is a subset of supportedCallingCodes" $
85− supportedGlobalNetworkCallingCodes `S.isSubsetOf` supportedCallingCodes
86−
87− describe "supportedCallingCodes" $ do
88− prop "doesn't contain 0" $ cc0 `S.notMember` supportedCallingCodes
89−
90− describe "supportedTypesForRegion" $ do
91− prop "doesn't contain FixedLineOrMobile" $ \(Reg region) ->
92− FixedLineOrMobile `S.notMember` supportedTypesForRegion region
93−
94− describe "supportedTypesForNonGeoEntity" $ do
95− prop "doesn't contain FixedLineOrMobile" $ \(CC cc) ->
96− FixedLineOrMobile `S.notMember` supportedTypesForNonGeoEntity cc
97−
98− describe "convertAlphaNumber" $ do
99− prop "doesn't change the parsing of a number" $ \(MReg mRegion) (ParserInput str) ->
100− parseNumber Canonicalize mRegion (convertAlphaNumber str)
101− === parseNumber Canonicalize mRegion str
102− prop "returns a number that is not alpha" $ \(ParserInput str) ->
103− not $ isAlphaNumber $ convertAlphaNumber str
104−
105− describe "normalizeNumber" $ do
106− prop "returns ASCII digits unmodified" $
107− forAll (elements [Digits, Dialable]) $ \mode ->
108− forAll (listOf $ elements ['0'..'9']) $ \str ->
109− BSC.pack str == normalizeNumber mode (BSC.pack str)
110− describe "Digits" $ do
111− prop "returns only ASCII digits" $ \str ->
112− BSC.all (`elem` ['0'..'9']) $ normalizeNumber Digits $ BSC.pack str
113− prop "doesn't randomly fail" $ \str ->
114− not (BS.null $ normalizeNumber Digits $ "0" <> BS.pack str)
115− .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
116− describe "Dialable" $ do
117− -- PhoneNumberUtil::NormalizeDiallableCharsOnly will error on any invalid UTF8
118− prop "doesn't randomly fail" $ \str ->
119− not (BS.null $ normalizeNumber Digits $ "0" <> BS.pack str)
120− .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
121−
122− describe "nationalSignificantNumber" $ do
123− prop "is non-empty" $ \(ParsedNumber _ pn) ->
124− not $ BS.null $ nationalSignificantNumber pn
125− prop "returns only ASCII digits" $ \(ParsedNumber _ pn) ->
126− BSC.all (`elem` ['0'..'9']) $ nationalSignificantNumber pn
127− modifyMaxDiscardRatio (* 10) $ do
128− prop "concatenated with country code parses to the original (if valid)" $
129− \(ParsedNumber _ pn) ->
130− isValidNumber Nothing pn ==>
131− let
132− cc = countryCode pn
133− nsn = nationalSignificantNumber pn
134− str = "+" <> BSC.pack (show cc) <> nsn
135− in case parseNumber Canonicalize Nothing str of
136− Left err -> error $ show err
137− Right pn' -> cc === countryCode pn'
138− .&&. nsn === nationalSignificantNumber pn'
139−
140− describe "countryMobileToken" $ do
141− prop "returns only ASCII digits" $ \(CC cc) ->
142− BSC.all (`elem` ['0'..'9']) $ countryMobileToken cc
143−
144− describe "formatNumber" $ do
145− prop "with International produces a parseable result (if no ext)" $
146− \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
147− -- Apparently in the TW region an extension number is formatted
148− -- with a "#", and the formatter will format
149− -- "+886 2 2123 4567 ext. 1234567890" as "+886 2 2123 4567#1234567890"
150− -- even though the former parses and the latter doesn't
151− extension pn == Nothing ==>
152− isRight $ parseNumber Canonicalize Nothing
153− $ formatNumber International pn
154− modifyMaxDiscardRatio (* 10) $ do
155− prop "with E164 produces a parseable result (if Canonicalize)" $
156− \(ParsedNumber (mode, _, _) pn) ->
157− -- KeepRawInput with pn == "0000" breaks E164 formatting
158− possibleNumber Unknown pn == IsPossible && mode == Canonicalize ==>
159− isRight $ parseNumber Canonicalize Nothing
160− $ formatNumber E164 pn
161− prop "with RFC3966 produces a parseable result (if Canonicalize)" $
162− \(ParsedNumber (mode, _, _) pn) ->
163− -- KeepRawInput with pn == "0000" breaks RFC3966 formatting
164− possibleNumber Unknown pn == IsPossible && mode == Canonicalize ==>
165− isRight $ parseNumber Canonicalize Nothing
166− $ formatNumber RFC3966 pn
167−
168− describe "truncateTooLongNumber" $ do
169− pure ()
170−
171− describe "numberType" $ do
172− pure ()
173−
174− describe "isValidNumber" $ do
175− modifyMaxDiscardRatio (* 10) $ do
176− prop "is preserved under parse . format" $ \(ParsedNumber _ pn) ->
177− isValidNumber Nothing pn ==>
178− case parseNumber Canonicalize Nothing $ formatNumber E164 pn of
179− Left err -> error $ show err
180− Right pn' -> isValidNumber Nothing pn'
181−
182− describe "regionForNumber" $ do
183− prop "doesn't return ZZ" $ \(ParsedNumber _ pn) ->
184− regionForNumber pn =/= Just (Right regZZ)
185− prop "doesn't return 001" $ \(ParsedNumber _ pn) ->
186− regionForNumber pn =/= Just (Right reg001)
187− prop "returns a supported region" $ \(ParsedNumber _ pn) ->
188− case regionForNumber pn of
189− Just (Right region) -> region `S.member` supportedRegions
190− _ -> discard
191− prop "returns Region001 exactly for supported non-geo entities" $
192− \(ParsedNumber _ pn) ->
193− (countryCode pn `S.member` supportedGlobalNetworkCallingCodes)
194− === (regionForNumber pn == Just (Left Region001))
195−
196− describe "countryCodeForRegion" $ do
197− prop "doesn't return 0" $ \(Reg region) ->
198− countryCodeForRegion region =/= Just cc0
199− prop "returns codes in supportedCallingCodes" $ \(Reg region) ->
200− case countryCodeForRegion region of
201− Nothing -> discard
202− Just cc -> cc `S.member` supportedCallingCodes
203−
204− describe "regionForCountryCode" $ do
205− prop "doesn't return ZZ" $ \(CC cc) ->
206− regionForCountryCode cc =/= Just (Right regZZ)
207− prop "doesn't return 001" $ \(CC cc) ->
208− regionForCountryCode cc =/= Just (Right reg001)
209− prop "returns Region001 exactly for supported non-geo entities" $ \(CC cc) ->
210− (cc `S.member` supportedGlobalNetworkCallingCodes)
211− === (regionForCountryCode cc == Just (Left Region001))
212−
213− describe "regionsForCountryCode" $ do
214− prop "doesn't return ZZ" $ \(CC cc) ->
215− Right regZZ `notElem` regionsForCountryCode cc
216− prop "doesn't return 001" $ \(CC cc) ->
217− Right reg001 `notElem` regionsForCountryCode cc
218−
219− describe "isNANPACountry" $ do
220− pure ()
221−
222− describe "nddPrefixForRegion" $ do
223− prop "with True returns only ASCII digits" $ \(Reg region) ->
224− BSC.all (`elem` ['0'..'9']) $ nddPrefixForRegion True region
225−
226− describe "possibleNumber" $ do
227− modifyMaxDiscardRatio (* 10) $ do
228− prop "with Unknown is more lenient than isValidNumber" $
229− \(ParsedNumber _ pn) -> isValidNumber Nothing pn ==>
230− possibleNumber Unknown pn `elem` [IsPossible, IsPossibleLocalOnly]
231−
232− describe "canBeInternationallyDialed" $ do
233− pure ()
234−
235− describe "isGeographicalNumber" $ do
236− prop "matches isGeographicalNumberType" $ \(ParsedNumber _ pn) ->
237− isGeographicalNumber pn
238− === isGeographicalNumberType (numberType pn) (countryCode pn)
239−
240− describe "isGeographicalNumberType" $ do
241− pure ()
242−
243− describe "parseNumber" $ do
244− prop "doesn't return a number with CountryCode 0" $ \(ParsedNumber _ pn) ->
245− countryCode pn /= cc0