git.iko.soy/typeable/libphonenumber
on 47cd576 help sign in
12 files changed+145−349
since splitsnapshots
unifiedsplit
.github/workflows/ci.yaml−102 LICENSE+1−1 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+40−58 src/Data/PhoneNumber/Internal/Number.chs+1−1 src/Data/PhoneNumber/Number.hs+10−69 src/Data/PhoneNumber/Util.hs+6−6 test/Spec.hs+27−34
.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"
LICENSE+1−1
@@ -1,6 +1,6 @@
11MIT License
22
3−Copyright (c) 2023 Typeable
3+Copyright (c) 2021 Typeable
44
55Permission is hereby granted, free of charge, to any person obtaining a copy
66of this software and associated documentation files (the "Software"), to deal
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+40−58
@@ -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
@@ -25,61 +24,44 @@ description:
2524 and to avoid a dependency on @text@, we use 'ByteString'
2625 throughout the library instead of 'Data.Text.Text'.
2726
28−copyright: 2023-2025 Typeable
27+copyright: 2023 Typeable
2928author: Typeable
3029maintainer: mniip@typeable.io
3130homepage: https://github.com/typeable/libphonenumber/
3231license: MIT
3332license-file: LICENSE
3433
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
34+build-type: Simple
4935
5036extra-source-files:
51− , include/*.h
52− , test/libphonenumber.supp
53−
54−source-repository head
55− type: git
56− location: https://github.com/typeable/libphonenumber/
37+ include/*.h
38+ test/libphonenumber.supp
5739
5840library
5941 exposed-modules:
60− , Data.PhoneNumber.Number
61− , Data.PhoneNumber.Util
42+ Data.PhoneNumber.Number
43+ Data.PhoneNumber.Util
6244 other-modules:
63− , Data.PhoneNumber.Internal.Common
64− , Data.PhoneNumber.Internal.Number
65− , Data.PhoneNumber.Internal.Util
45+ Data.PhoneNumber.Internal.Common
46+ Data.PhoneNumber.Internal.Number
47+ Data.PhoneNumber.Internal.Util
6648 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
49+ base >= 4.12 && < 4.18
50+ , bytestring
51+ , containers
52+ , deepseq
53+ , transformers
7254 build-tool-depends: c2hs:c2hs
73− pkgconfig-depends: protobuf
7455 include-dirs: include
7556 includes:
76− , c_phonenumber.h
77− , c_phonenumberutil.h
57+ c_phonenumber.h
58+ c_phonenumberutil.h
7859 cxx-sources:
79− , cxxbits/c_phonenumber.cpp
80− , cxxbits/c_phonenumberutil.cpp
60+ cxxbits/c_phonenumber.cpp
61+ cxxbits/c_phonenumberutil.cpp
8162 extra-libraries:
82− , phonenumber
63+ phonenumber
64+ protobuf
8365 if impl(ghc >= 9.4)
8466 build-depends: system-cxx-std-lib
8567 else
@@ -87,31 +69,31 @@ library
8769 hs-source-dirs: src
8870 default-language: Haskell2010
8971 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
72+ DeriveAnyClass
73+ DeriveDataTypeable
74+ DeriveGeneric
75+ DerivingStrategies
76+ GeneralizedNewtypeDeriving
77+ LambdaCase
78+ NamedFieldPuns
79+ OverloadedStrings
80+ PatternSynonyms
81+ StandaloneDeriving
82+ RecordWildCards
83+ ViewPatterns
10284 if impl(ghc >= 9.2)
10385 default-extensions: NoFieldSelectors
104− ghc-options: -Wall -Wextra
86+ ghc-options: -Wall -Wextra -Werror
10587
10688test-suite spec_test
10789 type: exitcode-stdio-1.0
10890 build-depends:
109− , base
91+ base
11092 , bytestring
11193 , containers
112− , hspec >= 2.10.8 && < 2.12
94+ , hspec
11395 , libphonenumber
114− , QuickCheck >= 2.13.1 && < 2.16
96+ , QuickCheck
11597 main-is: Spec.hs
11698 hs-source-dirs: test
11799 default-language: Haskell2010
@@ -120,9 +102,9 @@ test-suite spec_test
120102test-suite leak_test
121103 type: exitcode-stdio-1.0
122104 build-depends:
123− , base
105+ base
124106 , libphonenumber
125− , process >= 1.6.5 && < 1.7
107+ , process
126108 main-is: Leak.hs
127109 hs-source-dirs: test
128110 default-language: Haskell2010
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+6−6
@@ -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
test/Spec.hs+27−34
@@ -53,13 +53,11 @@ data ParsedNumber = ParsedNumber (ParseMode, Maybe Region, ParserInput) PhoneNum
5353 deriving stock (Show)
5454
5555instance 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
56+ arbitrary = liftA3 (,,) (elements [Canonicalize, KeepRawInput]) arbitrary arbitrary
57+ `suchThatMap` \(mode, MReg mRegion, ParserInput input) ->
58+ case parseNumber mode mRegion input of
59+ Right pn -> Just $ ParsedNumber (mode, mRegion, ParserInput input) pn
60+ _ -> Nothing
6361 shrink (ParsedNumber (mode, region, input) _) = do
6462 ParserInput input' <- shrink input
6563 case parseNumber mode region input' of
@@ -115,7 +113,7 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
115113 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
116114 describe "Dialable" $ do
117115 -- PhoneNumberUtil::NormalizeDiallableCharsOnly will error on any invalid UTF8
118− prop "doesn't randomly fail" $ \str ->
116+ xprop "doesn't randomly fail" $ \str ->
119117 not (BS.null $ normalizeNumber Digits $ "0" <> BS.pack str)
120118 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
121119
@@ -125,9 +123,14 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
125123 prop "returns only ASCII digits" $ \(ParsedNumber _ pn) ->
126124 BSC.all (`elem` ['0'..'9']) $ nationalSignificantNumber pn
127125 modifyMaxDiscardRatio (* 10) $ do
128− prop "concatenated with country code parses to the original (if valid)" $
129− \(ParsedNumber _ pn) ->
130− isValidNumber Nothing pn ==>
126+ prop "concatenated with country code parses to the original (if valid and not MX)" $
127+ \(ParsedNumber (_, _, ParserInput input) 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 ==>
131134 let
132135 cc = countryCode pn
133136 nsn = nationalSignificantNumber pn
@@ -142,28 +145,18 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
142145 BSC.all (`elem` ['0'..'9']) $ countryMobileToken cc
143146
144147 describe "formatNumber" $ do
145− prop "with International produces a parseable result (if no ext)" $
148+ prop "with International produces a parseable result" $
146149 \(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
150+ isRight $ parseNumber Canonicalize Nothing
151+ $ formatNumber International pn
152+ prop "with E164 produces a parseable result" $
153+ \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
154+ isRight $ parseNumber Canonicalize Nothing
155+ $ formatNumber E164 pn
156+ prop "with RFC3966 produces a parseable result" $
157+ \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
158+ isRight $ parseNumber Canonicalize Nothing
159+ $ formatNumber RFC3966 pn
167160
168161 describe "truncateTooLongNumber" $ do
169162 pure ()
@@ -226,8 +219,8 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
226219 describe "possibleNumber" $ do
227220 modifyMaxDiscardRatio (* 10) $ do
228221 prop "with Unknown is more lenient than isValidNumber" $
229− \(ParsedNumber _ pn) -> isValidNumber Nothing pn ==>
230− possibleNumber Unknown pn `elem` [IsPossible, IsPossibleLocalOnly]
222+ \(ParsedNumber _ pn) ->
223+ isValidNumber Nothing pn ==> possibleNumber Unknown pn === IsPossible
231224
232225 describe "canBeInternationallyDialed" $ do
233226 pure ()