git.iko.soy/typeable/libphonenumber
on main help sign in
.github/workflows/ci.yamlnew file+102
since splitsnapshots
unifiedsplit
@@ -0,0 +1,102 @@
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"
LICENSE+1−1
@@ -1,6 +1,6 @@
1MIT License
1MIT License
2
2
3−Copyright (c) 2021 Typeable
3+Copyright (c) 2023 Typeable
4
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
6of this software and associated documentation files (the "Software"), to deal
cxxbits/c_phonenumber.cpp+6−4
@@ -55,7 +55,7 @@ static country_code_source unmarshal_country_code_source(PhoneNumber::CountryCod
55 return static_cast<country_code_source>(value);
55 return static_cast<country_code_source>(value);
56}
56}
57
57
58−extern "C" PhoneNumber *c_phone_number_marshal(phone_number const *c_number)
58+extern "C" CxxPhoneNumber *c_phone_number_marshal(phone_number const *c_number)
59{
59{
60 PhoneNumber *number = new PhoneNumber();
60 PhoneNumber *number = new PhoneNumber();
61 if (c_number->extension != nullptr)
61 if (c_number->extension != nullptr)
@@ -72,11 +72,12 @@ extern "C" PhoneNumber *c_phone_number_marshal(phone_number const *c_number)
72 number->set_country_code_source(marshal_country_code_source(c_number->country_code_source));
72 number->set_country_code_source(marshal_country_code_source(c_number->country_code_source));
73 if (c_number->has_number_of_leading_zeros)
73 if (c_number->has_number_of_leading_zeros)
74 number->set_number_of_leading_zeros(c_number->number_of_leading_zeros);
74 number->set_number_of_leading_zeros(c_number->number_of_leading_zeros);
75− return number;
75+ return reinterpret_cast<CxxPhoneNumber *>(number);
76}
76}
77
77
78−extern "C" void c_phone_number_unmarshal(PhoneNumber const *number, phone_number *c_number)
78+extern "C" void c_phone_number_unmarshal(CxxPhoneNumber const *ptr, phone_number *c_number)
79{
79{
80+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
80 if (number->has_extension())
81 if (number->has_extension())
81 unmarshal_string_size(number->extension(), c_number->extension, c_number->extension_size);
82 unmarshal_string_size(number->extension(), c_number->extension, c_number->extension_size);
82 else
83 else
@@ -99,7 +100,8 @@ extern "C" void c_phone_number_unmarshal(PhoneNumber const *number, phone_number
99 c_number->number_of_leading_zeros = number->number_of_leading_zeros();
100 c_number->number_of_leading_zeros = number->number_of_leading_zeros();
100}
101}
101
102
102−extern "C" void c_phone_number_free(PhoneNumber *number)
103+extern "C" void c_phone_number_free(CxxPhoneNumber *ptr)
103{
104{
105+ auto number = reinterpret_cast<PhoneNumber *>(ptr);
104 delete number;
106 delete number;
105}
107}
cxxbits/c_phonenumberutil.cpp+45−26
@@ -310,10 +310,11 @@ extern "C" void c_phone_number_util_normalize_dialable_chars_only(
310}
310}
311
311
312extern "C" void c_phone_number_util_get_national_significant_number(
312extern "C" void c_phone_number_util_get_national_significant_number(
313− PhoneNumber const *number,
313+ CxxPhoneNumber const *ptr,
314 c_string *c_nsn
314 c_string *c_nsn
315)
315)
316{
316{
317+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
317 std::string nsn;
318 std::string nsn;
318 PhoneNumberUtil::GetInstance()->GetNationalSignificantNumber(*number, &nsn);
319 PhoneNumberUtil::GetInstance()->GetNationalSignificantNumber(*number, &nsn);
319 unmarshal_c_string(nsn, *c_nsn);
320 unmarshal_c_string(nsn, *c_nsn);
@@ -330,23 +331,25 @@ extern "C" void c_phone_number_util_get_country_mobile_token(
330}
331}
331
332
332extern "C" void c_phone_number_util_format(
333extern "C" void c_phone_number_util_format(
333− PhoneNumber const *number,
334+ CxxPhoneNumber const *ptr,
334 phone_number_format format,
335 phone_number_format format,
335 c_string *c_string
336 c_string *c_string
336)
337)
337{
338{
339+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
338 std::string string;
340 std::string string;
339 PhoneNumberUtil::GetInstance()->Format(*number, marshal_phone_number_format(format), &string);
341 PhoneNumberUtil::GetInstance()->Format(*number, marshal_phone_number_format(format), &string);
340 unmarshal_c_string(string, *c_string);
342 unmarshal_c_string(string, *c_string);
341}
343}
342
344
343extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
345extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
344− PhoneNumber const *number,
346+ CxxPhoneNumber const *ptr,
345 char const *c_carrier_code,
347 char const *c_carrier_code,
346 size_t c_carrier_code_size,
348 size_t c_carrier_code_size,
347 c_string *c_string
349 c_string *c_string
348)
350)
349{
351{
352+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
350 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
353 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
351 std::string string;
354 std::string string;
352 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithCarrierCode(*number, carrier_code, &string);
355 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithCarrierCode(*number, carrier_code, &string);
@@ -354,12 +357,13 @@ extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
354}
357}
355
358
356extern "C" void c_phone_number_util_format_national_number_with_preferred_carrier_code(
359extern "C" void c_phone_number_util_format_national_number_with_preferred_carrier_code(
357− PhoneNumber const *number,
360+ CxxPhoneNumber const *ptr,
358 char const *c_carrier_code,
361 char const *c_carrier_code,
359 size_t c_carrier_code_size,
362 size_t c_carrier_code_size,
360 c_string *c_string
363 c_string *c_string
361)
364)
362{
365{
366+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
363 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
367 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
364 std::string string;
368 std::string string;
365 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithPreferredCarrierCode(*number, carrier_code, &string);
369 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithPreferredCarrierCode(*number, carrier_code, &string);
@@ -367,13 +371,14 @@ extern "C" void c_phone_number_util_format_national_number_with_preferred_carrie
367}
371}
368
372
369extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
373extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
370− PhoneNumber const *number,
374+ CxxPhoneNumber const *ptr,
371 char const *c_region,
375 char const *c_region,
372 size_t c_region_size,
376 size_t c_region_size,
373 int with_formatting,
377 int with_formatting,
374 c_string *c_string
378 c_string *c_string
375)
379)
376{
380{
381+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
377 std::string const region(c_region, c_region_size);
382 std::string const region(c_region, c_region_size);
378 std::string string;
383 std::string string;
379 PhoneNumberUtil::GetInstance()->FormatNumberForMobileDialing(*number, region, with_formatting, &string);
384 PhoneNumberUtil::GetInstance()->FormatNumberForMobileDialing(*number, region, with_formatting, &string);
@@ -381,12 +386,13 @@ extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
381}
386}
382
387
383extern "C" void c_phone_number_util_format_out_of_country_calling_number(
388extern "C" void c_phone_number_util_format_out_of_country_calling_number(
384− PhoneNumber const *number,
389+ CxxPhoneNumber const *ptr,
385 char const *c_region,
390 char const *c_region,
386 size_t c_region_size,
391 size_t c_region_size,
387 c_string *c_string
392 c_string *c_string
388)
393)
389{
394{
395+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
390 std::string const region(c_region, c_region_size);
396 std::string const region(c_region, c_region_size);
391 std::string string;
397 std::string string;
392 PhoneNumberUtil::GetInstance()->FormatOutOfCountryCallingNumber(*number, region, &string);
398 PhoneNumberUtil::GetInstance()->FormatOutOfCountryCallingNumber(*number, region, &string);
@@ -394,12 +400,13 @@ extern "C" void c_phone_number_util_format_out_of_country_calling_number(
394}
400}
395
401
396extern "C" void c_phone_number_util_format_in_original_format(
402extern "C" void c_phone_number_util_format_in_original_format(
397− PhoneNumber const *number,
403+ CxxPhoneNumber const *ptr,
398 char const *c_region,
404 char const *c_region,
399 size_t c_region_size,
405 size_t c_region_size,
400 c_string *c_string
406 c_string *c_string
401)
407)
402{
408{
409+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
403 std::string const region(c_region, c_region_size);
410 std::string const region(c_region, c_region_size);
404 std::string string;
411 std::string string;
405 PhoneNumberUtil::GetInstance()->FormatInOriginalFormat(*number, region, &string);
412 PhoneNumberUtil::GetInstance()->FormatInOriginalFormat(*number, region, &string);
@@ -407,24 +414,26 @@ extern "C" void c_phone_number_util_format_in_original_format(
407}
414}
408
415
409extern "C" void c_phone_number_util_format_out_of_country_keeping_alpha_chars(
416extern "C" void c_phone_number_util_format_out_of_country_keeping_alpha_chars(
410− PhoneNumber const *number,
417+ CxxPhoneNumber const *ptr,
411 char const *c_region,
418 char const *c_region,
412 size_t c_region_size,
419 size_t c_region_size,
413 c_string *c_string
420 c_string *c_string
414)
421)
415{
422{
423+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
416 std::string const region(c_region, c_region_size);
424 std::string const region(c_region, c_region_size);
417 std::string string;
425 std::string string;
418 PhoneNumberUtil::GetInstance()->FormatOutOfCountryKeepingAlphaChars(*number, region, &string);
426 PhoneNumberUtil::GetInstance()->FormatOutOfCountryKeepingAlphaChars(*number, region, &string);
419 unmarshal_c_string(string, *c_string);
427 unmarshal_c_string(string, *c_string);
420}
428}
421
429
422−extern "C" PhoneNumber *c_phone_number_util_truncate_too_long_number(PhoneNumber const *input)
430+extern "C" CxxPhoneNumber *c_phone_number_util_truncate_too_long_number(CxxPhoneNumber const *ptr)
423{
431{
432+ auto input = reinterpret_cast<PhoneNumber const *>(ptr);
424 auto *output = new PhoneNumber(*input);
433 auto *output = new PhoneNumber(*input);
425 if (PhoneNumberUtil::GetInstance()->TruncateTooLongNumber(output))
434 if (PhoneNumberUtil::GetInstance()->TruncateTooLongNumber(output))
426 {
435 {
427− return output;
436+ return reinterpret_cast<CxxPhoneNumber *>(output);
428 }
437 }
429 else
438 else
430 {
439 {
@@ -433,33 +442,37 @@ extern "C" PhoneNumber *c_phone_number_util_truncate_too_long_number(PhoneNumber
433 }
442 }
434}
443}
435
444
436−extern "C" phone_number_type c_phone_number_util_get_number_type(PhoneNumber const *number)
445+extern "C" phone_number_type c_phone_number_util_get_number_type(CxxPhoneNumber const *ptr)
437{
446{
447+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
438 return unmarshal_phone_number_type(
448 return unmarshal_phone_number_type(
439 PhoneNumberUtil::GetInstance()->GetNumberType(*number)
449 PhoneNumberUtil::GetInstance()->GetNumberType(*number)
440 );
450 );
441}
451}
442
452
443−extern "C" int c_phone_number_util_is_valid_number(PhoneNumber const *number)
453+extern "C" int c_phone_number_util_is_valid_number(CxxPhoneNumber const *ptr)
444{
454{
455+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
445 return PhoneNumberUtil::GetInstance()->IsValidNumber(*number);
456 return PhoneNumberUtil::GetInstance()->IsValidNumber(*number);
446}
457}
447
458
448extern "C" int c_phone_number_util_is_valid_number_for_region(
459extern "C" int c_phone_number_util_is_valid_number_for_region(
449− PhoneNumber const *number,
460+ CxxPhoneNumber const *ptr,
450 char const *c_region,
461 char const *c_region,
451 size_t c_region_size
462 size_t c_region_size
452)
463)
453{
464{
465+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
454 std::string const region(c_region, c_region_size);
466 std::string const region(c_region, c_region_size);
455 return PhoneNumberUtil::GetInstance()->IsValidNumberForRegion(*number, region);
467 return PhoneNumberUtil::GetInstance()->IsValidNumberForRegion(*number, region);
456}
468}
457
469
458extern "C" void c_phone_number_util_get_region_code_for_number(
470extern "C" void c_phone_number_util_get_region_code_for_number(
459− PhoneNumber const *number,
471+ CxxPhoneNumber const *ptr,
460 c_string *c_region
472 c_string *c_region
461)
473)
462{
474{
475+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
463 std::string region;
476 std::string region;
464 PhoneNumberUtil::GetInstance()->GetRegionCodeForNumber(*number, &region);
477 PhoneNumberUtil::GetInstance()->GetRegionCodeForNumber(*number, &region);
465 unmarshal_c_string(region, *c_region);
478 unmarshal_c_string(region, *c_region);
@@ -518,10 +531,11 @@ extern "C" void c_phone_number_util_get_ndd_prefix_for_region(
518}
531}
519
532
520extern "C" validation_result c_phone_number_util_is_possible_number_for_type_with_reason(
533extern "C" validation_result c_phone_number_util_is_possible_number_for_type_with_reason(
521− PhoneNumber const *number,
534+ CxxPhoneNumber const *ptr,
522 phone_number_type ntype
535 phone_number_type ntype
523)
536)
524{
537{
538+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
525 return unmarshal_validation_result(
539 return unmarshal_validation_result(
526 PhoneNumberUtil::GetInstance()->IsPossibleNumberForTypeWithReason(
540 PhoneNumberUtil::GetInstance()->IsPossibleNumberForTypeWithReason(
527 *number,
541 *number,
@@ -530,13 +544,15 @@ extern "C" validation_result c_phone_number_util_is_possible_number_for_type_wit
530 );
544 );
531}
545}
532
546
533−extern "C" int c_phone_number_util_can_be_internationally_dialed(PhoneNumber const *number)
547+extern "C" int c_phone_number_util_can_be_internationally_dialed(CxxPhoneNumber const *ptr)
534{
548{
549+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
535 return PhoneNumberUtil::GetInstance()->CanBeInternationallyDialled(*number);
550 return PhoneNumberUtil::GetInstance()->CanBeInternationallyDialled(*number);
536}
551}
537
552
538−extern "C" int c_phone_number_util_is_number_geographical_1(PhoneNumber const *number)
553+extern "C" int c_phone_number_util_is_number_geographical_1(CxxPhoneNumber const *ptr)
539{
554{
555+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
540 return PhoneNumberUtil::GetInstance()->IsNumberGeographical(*number);
556 return PhoneNumberUtil::GetInstance()->IsNumberGeographical(*number);
541}
557}
542
558
@@ -556,14 +572,14 @@ extern "C" error_type c_phone_number_util_parse(
556 size_t c_string_size,
572 size_t c_string_size,
557 char const *c_region,
573 char const *c_region,
558 size_t c_region_size,
574 size_t c_region_size,
559− PhoneNumber **number
575+ CxxPhoneNumber **number
560)
576)
561{
577{
562 std::string const string(c_string, c_string_size);
578 std::string const string(c_string, c_string_size);
563 std::string const region(c_region, c_region_size);
579 std::string const region(c_region, c_region_size);
564− *number = new PhoneNumber();
580+ *number = reinterpret_cast<CxxPhoneNumber *>(new PhoneNumber());
565 return unmarshal_error_type(
581 return unmarshal_error_type(
566− PhoneNumberUtil::GetInstance()->Parse(string, region, *number)
582+ PhoneNumberUtil::GetInstance()->Parse(string, region, reinterpret_cast<PhoneNumber *>(*number))
567 );
583 );
568}
584}
569
585
@@ -572,22 +588,24 @@ extern "C" error_type c_phone_number_util_parse_and_keep_raw_input(
572 size_t c_string_size,
588 size_t c_string_size,
573 char const *c_region,
589 char const *c_region,
574 size_t c_region_size,
590 size_t c_region_size,
575− PhoneNumber **number
591+ CxxPhoneNumber **number
576)
592)
577{
593{
578 std::string const string(c_string, c_string_size);
594 std::string const string(c_string, c_string_size);
579 std::string const region(c_region, c_region_size);
595 std::string const region(c_region, c_region_size);
580− *number = new PhoneNumber();
596+ *number = reinterpret_cast<CxxPhoneNumber *>(new PhoneNumber());
581 return unmarshal_error_type(
597 return unmarshal_error_type(
582− PhoneNumberUtil::GetInstance()->ParseAndKeepRawInput(string, region, *number)
598+ PhoneNumberUtil::GetInstance()->ParseAndKeepRawInput(string, region, reinterpret_cast<PhoneNumber *>(*number))
583 );
599 );
584}
600}
585
601
586extern "C" match_type c_phone_number_util_is_number_match(
602extern "C" match_type c_phone_number_util_is_number_match(
587− PhoneNumber const *number1,
603+ CxxPhoneNumber const *ptr1,
588− PhoneNumber const *number2
604+ CxxPhoneNumber const *ptr2
589)
605)
590{
606{
607+ auto number1 = reinterpret_cast<PhoneNumber const *>(ptr1);
608+ auto number2 = reinterpret_cast<PhoneNumber const *>(ptr2);
591 return unmarshal_match_type(
609 return unmarshal_match_type(
592 PhoneNumberUtil::GetInstance()->IsNumberMatch(*number1, *number2)
610 PhoneNumberUtil::GetInstance()->IsNumberMatch(*number1, *number2)
593 );
611 );
@@ -608,11 +626,12 @@ extern "C" match_type c_phone_number_util_is_number_match_with_two_strings(
608}
626}
609
627
610extern "C" match_type c_phone_number_util_is_number_match_with_one_string(
628extern "C" match_type c_phone_number_util_is_number_match_with_one_string(
611− PhoneNumber const *number1,
629+ CxxPhoneNumber const *ptr1,
612 char const *c_number2,
630 char const *c_number2,
613 size_t c_number2_size
631 size_t c_number2_size
614)
632)
615{
633{
634+ auto number1 = reinterpret_cast<PhoneNumber const *>(ptr1);
616 std::string const number2(c_number2, c_number2_size);
635 std::string const number2(c_number2, c_number2_size);
617 return unmarshal_match_type(
636 return unmarshal_match_type(
618 PhoneNumberUtil::GetInstance()->IsNumberMatchWithOneString(*number1, number2)
637 PhoneNumberUtil::GetInstance()->IsNumberMatchWithOneString(*number1, number2)
include/c_phonenumber.h+4−8
@@ -43,20 +43,16 @@ typedef struct
43 char has_number_of_leading_zeros;
43 char has_number_of_leading_zeros;
44} phone_number;
44} phone_number;
45
45
46−#ifdef __cplusplus
46+struct CxxPhoneNumber;
47−typedef i18n::phonenumbers::PhoneNumber PhoneNumber;
48−#else
49−typedef struct PhoneNumber PhoneNumber;
50−#endif
51
47
52// The returned object is allocated by `new` and managed by C++ RAII, and it is
48// The returned object is allocated by `new` and managed by C++ RAII, and it is
53// haskell's responsibility to call its finalizer (c_phone_number_free).
49// haskell's responsibility to call its finalizer (c_phone_number_free).
54−PhoneNumber *c_phone_number_marshal(phone_number const *);
50+struct CxxPhoneNumber *c_phone_number_marshal(phone_number const *);
55
51
56// phone_number * points to an area which will be filled with the data of the
52// phone_number * points to an area which will be filled with the data of the
57// given PhoneNumber.
53// given PhoneNumber.
58−void c_phone_number_unmarshal(PhoneNumber const *, phone_number *);
54+void c_phone_number_unmarshal(struct CxxPhoneNumber const *, phone_number *);
59
55
60−void c_phone_number_free(PhoneNumber *);
56+void c_phone_number_free(struct CxxPhoneNumber *);
61
57
62#endif
58#endif
include/c_phonenumberutil.h+20−20
@@ -97,34 +97,34 @@ int c_phone_number_util_is_alpha_number(char const *, size_t);
97void c_phone_number_util_convert_alpha_characters_in_number(char const *, size_t, c_string *);
97void c_phone_number_util_convert_alpha_characters_in_number(char const *, size_t, c_string *);
98void c_phone_number_util_normalize_digits_only(char const *, size_t, c_string *);
98void c_phone_number_util_normalize_digits_only(char const *, size_t, c_string *);
99void c_phone_number_util_normalize_dialable_chars_only(char const *, size_t, c_string *);
99void c_phone_number_util_normalize_dialable_chars_only(char const *, size_t, c_string *);
100−void c_phone_number_util_get_national_significant_number(PhoneNumber const *, c_string *);
100+void c_phone_number_util_get_national_significant_number(struct CxxPhoneNumber const *, c_string *);
101void c_phone_number_util_get_country_mobile_token(int, c_string *);
101void c_phone_number_util_get_country_mobile_token(int, c_string *);
102−void c_phone_number_util_format(PhoneNumber const *, enum phone_number_format, 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(PhoneNumber const *, char const *, size_t, 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(PhoneNumber 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(PhoneNumber const *, char const *, size_t, int, 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(PhoneNumber const *, char const *, size_t, 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(PhoneNumber 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(PhoneNumber 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 *);
109// /!\ May return NULL
109// /!\ May return NULL
110−PhoneNumber *c_phone_number_util_truncate_too_long_number(PhoneNumber const *);
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(PhoneNumber 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(PhoneNumber const *);
112+int c_phone_number_util_is_valid_number(struct CxxPhoneNumber const *);
113−int c_phone_number_util_is_valid_number_for_region(PhoneNumber const *, char const *, size_t);
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(PhoneNumber const *, c_string *);
114+void c_phone_number_util_get_region_code_for_number(struct CxxPhoneNumber const *, c_string *);
115int c_phone_number_util_get_country_code_for_region(char const *, size_t);
115int c_phone_number_util_get_country_code_for_region(char const *, size_t);
116void c_phone_number_util_get_region_code_for_country_code(int, c_string *);
116void c_phone_number_util_get_region_code_for_country_code(int, c_string *);
117void c_phone_number_util_get_region_codes_for_country_calling_code(int, c_string **, size_t *);
117void c_phone_number_util_get_region_codes_for_country_calling_code(int, c_string **, size_t *);
118int c_phone_number_util_is_nanpa_country(char const *, size_t);
118int c_phone_number_util_is_nanpa_country(char const *, size_t);
119void c_phone_number_util_get_ndd_prefix_for_region(char const *, size_t, int, c_string *);
119void 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(PhoneNumber const *, enum phone_number_type);
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(PhoneNumber const *);
121+int c_phone_number_util_can_be_internationally_dialed(struct CxxPhoneNumber const *);
122−int c_phone_number_util_is_number_geographical_1(PhoneNumber const *);
122+int c_phone_number_util_is_number_geographical_1(struct CxxPhoneNumber const *);
123int c_phone_number_util_is_number_geographical_2(enum phone_number_type, int);
123int 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, PhoneNumber **);
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, PhoneNumber **);
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(PhoneNumber const *, PhoneNumber const *);
126+enum match_type c_phone_number_util_is_number_match(struct CxxPhoneNumber const *, struct CxxPhoneNumber const *);
127enum match_type c_phone_number_util_is_number_match_with_two_strings(char const *, size_t, char const *, size_t);
127enum 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(PhoneNumber const *, 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);
129
129
130#endif
130#endif
include/common.h+3−2
@@ -4,6 +4,7 @@
4#include <cstddef>
4#include <cstddef>
5#include <cstring>
5#include <cstring>
6#include <type_traits>
6#include <type_traits>
7+#include <utility>
7
8
8// Given `enum T { A, B, C }` and `enum S { X, Y, Z }`, we can use
9// Given `enum T { A, B, C }` and `enum S { X, Y, Z }`, we can use
9// `is_same_enum<enum_values<T, A, B, C>, enum_values<S, X, Y, Z>>::value`
10// `is_same_enum<enum_values<T, A, B, C>, enum_values<S, X, Y, Z>>::value`
@@ -31,7 +32,7 @@ struct is_same_enum: std::false_type
31
32
32template<typename T, T... TVals, typename S, S... SVals>
33template<typename T, T... TVals, typename S, S... SVals>
33struct is_same_enum<enum_values<T, TVals...>, enum_values<S, SVals...>>:
34struct is_same_enum<enum_values<T, TVals...>, enum_values<S, SVals...>>:
34− std::integral_constant<bool, std::is_same_v<
35+ std::integral_constant<bool, std::is_same<
35 std::integer_sequence<
36 std::integer_sequence<
36 typename std::common_type<
37 typename std::common_type<
37 typename std::underlying_type<T>::type,
38 typename std::underlying_type<T>::type,
@@ -46,7 +47,7 @@ struct is_same_enum<enum_values<T, TVals...>, enum_values<S, SVals...>>:
46 >::type,
47 >::type,
47 SVals...
48 SVals...
48 >
49 >
49− >>
50+ >::value>
50{};
51{};
51
52
52inline void unmarshal_string_size(std::string const &string, char *&c_string, size_t &c_string_size)
53inline void unmarshal_string_size(std::string const &string, char *&c_string, size_t &c_string_size)
libphonenumber.cabal+58−40
@@ -1,6 +1,6 @@
1cabal-version: 3.0
1cabal-version: 3.0
2name: libphonenumber
2name: libphonenumber
3−version: 0.0.0.0
3+version: 0.1.4.0
4category: Data
4category: Data
5synopsis: Parsing, formatting, and validating international phone
5synopsis: Parsing, formatting, and validating international phone
6 numbers
6 numbers
@@ -8,7 +8,8 @@ description:
8 This package provides bindings for the C++ version of the
8 This package provides bindings for the C++ version of the
9 <https://github.com/google/libphonenumber libphonenumber library>.
9 <https://github.com/google/libphonenumber libphonenumber library>.
10 The bindings currently do not include @AsYouTypeFormatter@
10 The bindings currently do not include @AsYouTypeFormatter@
11− and @ShortNumberInfo@.
11+ and @ShortNumberInfo@. The C++ library must be of version
12+ >= 8.7.0.
12
13
13 The interface largely resembles that of the original unified
14 The interface largely resembles that of the original unified
14 C++, Java, and JavaScript version of the library, with some
15 C++, Java, and JavaScript version of the library, with some
@@ -24,44 +25,61 @@ description:
24 and to avoid a dependency on @text@, we use 'ByteString'
25 and to avoid a dependency on @text@, we use 'ByteString'
25 throughout the library instead of 'Data.Text.Text'.
26 throughout the library instead of 'Data.Text.Text'.
26
27
27−copyright: 2023 Typeable
28+copyright: 2023-2025 Typeable
28author: Typeable
29author: Typeable
29maintainer: mniip@typeable.io
30maintainer: mniip@typeable.io
30homepage: https://github.com/typeable/libphonenumber/
31homepage: https://github.com/typeable/libphonenumber/
31license: MIT
32license: MIT
32license-file: LICENSE
33license-file: LICENSE
33
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+
34−build-type: Simple
48+build-type: Simple
35
49
36extra-source-files:
50extra-source-files:
37− include/*.h
51+ , include/*.h
38− test/libphonenumber.supp
52+ , test/libphonenumber.supp
53+
54+source-repository head
55+ type: git
56+ location: https://github.com/typeable/libphonenumber/
39
57
40library
58library
41 exposed-modules:
59 exposed-modules:
42− Data.PhoneNumber.Number
60+ , Data.PhoneNumber.Number
43− Data.PhoneNumber.Util
61+ , Data.PhoneNumber.Util
44 other-modules:
62 other-modules:
45− Data.PhoneNumber.Internal.Common
63+ , Data.PhoneNumber.Internal.Common
46− Data.PhoneNumber.Internal.Number
64+ , Data.PhoneNumber.Internal.Number
47− Data.PhoneNumber.Internal.Util
65+ , Data.PhoneNumber.Internal.Util
48 build-depends:
66 build-depends:
49− base >= 4.12 && < 4.18
67+ , base >= 4.12 && < 4.23
50− , bytestring
68+ , bytestring >= 0.10.8 && < 0.13
51− , containers
69+ , containers >= 0.6.0 && < 0.9
52− , deepseq
70+ , deepseq >= 1.4.4 && < 1.6
53− , transformers
71+ , transformers >= 0.5.5 && < 0.7
54 build-tool-depends: c2hs:c2hs
72 build-tool-depends: c2hs:c2hs
73+ pkgconfig-depends: protobuf
55 include-dirs: include
74 include-dirs: include
56 includes:
75 includes:
57− c_phonenumber.h
76+ , c_phonenumber.h
58− c_phonenumberutil.h
77+ , c_phonenumberutil.h
59 cxx-sources:
78 cxx-sources:
60− cxxbits/c_phonenumber.cpp
79+ , cxxbits/c_phonenumber.cpp
61− cxxbits/c_phonenumberutil.cpp
80+ , cxxbits/c_phonenumberutil.cpp
62 extra-libraries:
81 extra-libraries:
63− phonenumber
82+ , phonenumber
64− protobuf
65 if impl(ghc >= 9.4)
83 if impl(ghc >= 9.4)
66 build-depends: system-cxx-std-lib
84 build-depends: system-cxx-std-lib
67 else
85 else
@@ -69,31 +87,31 @@ library
69 hs-source-dirs: src
87 hs-source-dirs: src
70 default-language: Haskell2010
88 default-language: Haskell2010
71 default-extensions:
89 default-extensions:
72− DeriveAnyClass
90+ , DeriveAnyClass
73− DeriveDataTypeable
91+ , DeriveDataTypeable
74− DeriveGeneric
92+ , DeriveGeneric
75− DerivingStrategies
93+ , DerivingStrategies
76− GeneralizedNewtypeDeriving
94+ , GeneralizedNewtypeDeriving
77− LambdaCase
95+ , LambdaCase
78− NamedFieldPuns
96+ , NamedFieldPuns
79− OverloadedStrings
97+ , OverloadedStrings
80− PatternSynonyms
98+ , PatternSynonyms
81− StandaloneDeriving
99+ , StandaloneDeriving
82− RecordWildCards
100+ , RecordWildCards
83− ViewPatterns
101+ , ViewPatterns
84 if impl(ghc >= 9.2)
102 if impl(ghc >= 9.2)
85 default-extensions: NoFieldSelectors
103 default-extensions: NoFieldSelectors
86− ghc-options: -Wall -Wextra -Werror
104+ ghc-options: -Wall -Wextra
87
105
88test-suite spec_test
106test-suite spec_test
89 type: exitcode-stdio-1.0
107 type: exitcode-stdio-1.0
90 build-depends:
108 build-depends:
91− base
109+ , base
92 , bytestring
110 , bytestring
93 , containers
111 , containers
94− , hspec
112+ , hspec >= 2.10.8 && < 2.12
95 , libphonenumber
113 , libphonenumber
96− , QuickCheck
114+ , QuickCheck >= 2.13.1 && < 2.16
97 main-is: Spec.hs
115 main-is: Spec.hs
98 hs-source-dirs: test
116 hs-source-dirs: test
99 default-language: Haskell2010
117 default-language: Haskell2010
@@ -102,9 +120,9 @@ test-suite spec_test
102test-suite leak_test
120test-suite leak_test
103 type: exitcode-stdio-1.0
121 type: exitcode-stdio-1.0
104 build-depends:
122 build-depends:
105− base
123+ , base
106 , libphonenumber
124 , libphonenumber
107− , process
125+ , process >= 1.6.5 && < 1.7
108 main-is: Leak.hs
126 main-is: Leak.hs
109 hs-source-dirs: test
127 hs-source-dirs: test
110 default-language: Haskell2010
128 default-language: Haskell2010
src/Data/PhoneNumber/Internal/Number.chs+1−1
@@ -126,7 +126,7 @@ acquireCPhoneNumber p = do
126-- , 'Data.PhoneNumber.Number.numberOfLeadingZeros' :: !('Maybe' 'Int')
126-- , 'Data.PhoneNumber.Number.numberOfLeadingZeros' :: !('Maybe' 'Int')
127-- }
127-- }
128-- @
128-- @
129−{#pointer *PhoneNumber foreign finalizer c_phone_number_free newtype#}
129+{#pointer *CxxPhoneNumber as PhoneNumber foreign finalizer c_phone_number_free newtype#}
130
130
131{#fun unsafe c_phone_number_marshal
131{#fun unsafe c_phone_number_marshal
132 { withCPhoneNumber* `CPhoneNumber'
132 { withCPhoneNumber* `CPhoneNumber'
src/Data/PhoneNumber/Number.hs+69−10
@@ -21,16 +21,10 @@ module Data.PhoneNumber.Number
21 ) where
21 ) where
22
22
23import Data.ByteString (ByteString)
23import Data.ByteString (ByteString)
24−import Data.PhoneNumber.Internal.Number hiding
24+import Data.PhoneNumber.Internal.Number
25− ( pattern PhoneNumber
25+ ( CPhoneNumber(CPhoneNumber), PhoneNumber, CountryCodeSource, toCPhoneNumber
26− , extension
26+ , fromCPhoneNumber
27− , rawInput
27+ )
28− , preferredDomesticCarrierCode
29− , nationalNumber
30− , countryCode
31− , italianLeadingZero
32− , countryCodeSource
33− , numberOfLeadingZeros )
34import qualified Data.PhoneNumber.Internal.Number as I
28import qualified Data.PhoneNumber.Internal.Number as I
35
29
36-- | A country calling code (International Subscriber Dialing code, ISD code),
30-- | A country calling code (International Subscriber Dialing code, ISD code),
@@ -79,3 +73,68 @@ pattern PhoneNumber
79 = fromCPhoneNumber $ CPhoneNumber{..}
73 = fromCPhoneNumber $ CPhoneNumber{..}
80
74
81{-# COMPLETE PhoneNumber #-}
75{-# 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+6−6
@@ -371,12 +371,12 @@ nddPrefixForRegion strip (Region region) = unsafeDupablePerformIO $ mask_ $
371-- 3. For some numbers (particularly fixed-line), many regions have the concept
371-- 3. For some numbers (particularly fixed-line), many regions have the concept
372-- of area code, which together with subscriber number constitute the National
372-- of area code, which together with subscriber number constitute the National
373-- Significant Number. It is sometimes okay to dial only the subscriber number
373-- Significant Number. It is sometimes okay to dial only the subscriber number
374−-- when dialing in the same area. This function will return IsPossibleLocalOnly
374+-- when dialing in the same area. This function will return
375−-- if the subscriber-number-only version is passed in. On the other hand,
375+-- 'IsPossibleLocalOnly' if the subscriber-number-only version is passed in. On
376−-- because 'isValidNumber' validates using information on both starting digits
376+-- the other hand, because 'isValidNumber' validates using information on both
377−-- (for fixed line numbers, that would most likely be area codes) and length
377+-- starting digits (for fixed line numbers, that would most likely be area
378−-- (obviously includes the length of area codes for fixed line numbers), it will
378+-- codes) and length (obviously includes the length of area codes for fixed line
379−-- return 'False' for the subscriber-number-only version.
379+-- numbers), it will return 'False' for the subscriber-number-only version.
380possibleNumber :: PhoneNumberType -> PhoneNumber -> ValidationResult
380possibleNumber :: PhoneNumberType -> PhoneNumber -> ValidationResult
381possibleNumber ntype pn = unsafeDupablePerformIO $
381possibleNumber ntype pn = unsafeDupablePerformIO $
382 c_phone_number_util_is_possible_number_for_type_with_reason pn ntype
382 c_phone_number_util_is_possible_number_for_type_with_reason pn ntype
test/Spec.hs+34−27
@@ -53,11 +53,13 @@ data ParsedNumber = ParsedNumber (ParseMode, Maybe Region, ParserInput) PhoneNum
53 deriving stock (Show)
53 deriving stock (Show)
54
54
55instance Arbitrary ParsedNumber where
55instance Arbitrary ParsedNumber where
56+ arbitrary = do
56− arbitrary = liftA3 (,,) (elements [Canonicalize, KeepRawInput]) arbitrary arbitrary
57+ mode <- elements [Canonicalize, KeepRawInput]
58+ liftA2 ((,,) mode) arbitrary arbitrary
57− `suchThatMap` \(mode, MReg mRegion, ParserInput input) ->
59+ `suchThatMap` \(_, MReg mRegion, ParserInput input) ->
58− case parseNumber mode mRegion input of
60+ case parseNumber mode mRegion input of
59− Right pn -> Just $ ParsedNumber (mode, mRegion, ParserInput input) pn
61+ Right pn -> Just $ ParsedNumber (mode, mRegion, ParserInput input) pn
60− _ -> Nothing
62+ _ -> Nothing
61 shrink (ParsedNumber (mode, region, input) _) = do
63 shrink (ParsedNumber (mode, region, input) _) = do
62 ParserInput input' <- shrink input
64 ParserInput input' <- shrink input
63 case parseNumber mode region input' of
65 case parseNumber mode region input' of
@@ -113,7 +115,7 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
113 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
115 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
114 describe "Dialable" $ do
116 describe "Dialable" $ do
115 -- PhoneNumberUtil::NormalizeDiallableCharsOnly will error on any invalid UTF8
117 -- PhoneNumberUtil::NormalizeDiallableCharsOnly will error on any invalid UTF8
116− xprop "doesn't randomly fail" $ \str ->
118+ prop "doesn't randomly fail" $ \str ->
117 not (BS.null $ normalizeNumber Digits $ "0" <> BS.pack str)
119 not (BS.null $ normalizeNumber Digits $ "0" <> BS.pack str)
118 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
120 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
119
121
@@ -123,14 +125,9 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
123 prop "returns only ASCII digits" $ \(ParsedNumber _ pn) ->
125 prop "returns only ASCII digits" $ \(ParsedNumber _ pn) ->
124 BSC.all (`elem` ['0'..'9']) $ nationalSignificantNumber pn
126 BSC.all (`elem` ['0'..'9']) $ nationalSignificantNumber pn
125 modifyMaxDiscardRatio (* 10) $ do
127 modifyMaxDiscardRatio (* 10) $ do
126− prop "concatenated with country code parses to the original (if valid and not MX)" $
128+ prop "concatenated with country code parses to the original (if valid)" $
127− \(ParsedNumber (_, _, ParserInput input) pn) ->
129+ \(ParsedNumber _ pn) ->
128− -- Apparently "+52112210000000" makes the parser/formatter do weird
129− -- stuff as it tries to handle the deprecated (?) mobile token ("1"
130− -- after "+52")
131− if "5211" `BS.isPrefixOf` normalizeNumber Digits input
132− then discard
133− else isValidNumber Nothing pn ==>
130+ isValidNumber Nothing pn ==>
134 let
131 let
135 cc = countryCode pn
132 cc = countryCode pn
136 nsn = nationalSignificantNumber pn
133 nsn = nationalSignificantNumber pn
@@ -145,18 +142,28 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
145 BSC.all (`elem` ['0'..'9']) $ countryMobileToken cc
142 BSC.all (`elem` ['0'..'9']) $ countryMobileToken cc
146
143
147 describe "formatNumber" $ do
144 describe "formatNumber" $ do
148− prop "with International produces a parseable result" $
145+ prop "with International produces a parseable result (if no ext)" $
149− \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
150− isRight $ parseNumber Canonicalize Nothing
151− $ formatNumber International pn
152− prop "with E164 produces a parseable result" $
153 \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
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 ==>
154− isRight $ parseNumber Canonicalize Nothing
152+ isRight $ parseNumber Canonicalize Nothing
155− $ formatNumber E164 pn
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
156− prop "with RFC3966 produces a parseable result" $
161+ prop "with RFC3966 produces a parseable result (if Canonicalize)" $
162+ \(ParsedNumber (mode, _, _) pn) ->
163+ -- KeepRawInput with pn == "0000" breaks RFC3966 formatting
157− \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
164+ possibleNumber Unknown pn == IsPossible && mode == Canonicalize ==>
158− isRight $ parseNumber Canonicalize Nothing
165+ isRight $ parseNumber Canonicalize Nothing
159− $ formatNumber RFC3966 pn
166+ $ formatNumber RFC3966 pn
160
167
161 describe "truncateTooLongNumber" $ do
168 describe "truncateTooLongNumber" $ do
162 pure ()
169 pure ()
@@ -219,8 +226,8 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
219 describe "possibleNumber" $ do
226 describe "possibleNumber" $ do
220 modifyMaxDiscardRatio (* 10) $ do
227 modifyMaxDiscardRatio (* 10) $ do
221 prop "with Unknown is more lenient than isValidNumber" $
228 prop "with Unknown is more lenient than isValidNumber" $
222− \(ParsedNumber _ pn) ->
229+ \(ParsedNumber _ pn) -> isValidNumber Nothing pn ==>
223− isValidNumber Nothing pn ==> possibleNumber Unknown pn === IsPossible
230+ possibleNumber Unknown pn `elem` [IsPossible, IsPossibleLocalOnly]
224
231
225 describe "canBeInternationallyDialed" $ do
232 describe "canBeInternationallyDialed" $ do
226 pure ()
233 pure ()