git.iko.soy/typeable/libphonenumber
on main help sign in
12 files changed+209−122
since splitsnapshots
unifiedsplit
.github/workflows/ci.yaml+12−8 LICENSE+1−1 cxxbits/c_phonenumber.cpp+6−4 cxxbits/c_phonenumberutil.cpp+45−26 include/c_phonenumber.h+4−8 include/c_phonenumberutil.h+20−20 include/common.h+3−2 libphonenumber.cabal+18−13 src/Data/PhoneNumber/Internal/Number.chs+1−1 src/Data/PhoneNumber/Number.hs+69−10 src/Data/PhoneNumber/Util.hs+6−6 test/Spec.hs+24−23
.github/workflows/ci.yaml+12−8
@@ -22,15 +22,19 @@ jobs:
2222 - "8.8.4"
2323 - "8.10.7"
2424 - "9.0.2"
25− - "9.2.7"
26− - "9.4.4"
27− - "9.6.1"
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"
2832 fail-fast: false
2933 name: Build on Linux, GHC ${{ matrix.ghc_version }}
3034 runs-on: ${{ matrix.platform }}
3135 steps:
32− - uses: actions/checkout@v3
33− - uses: haskell/actions/setup@v2
36+ - uses: actions/checkout@v4
37+ - uses: haskell-actions/setup@v2
3438 with:
3539 ghc-version: ${{ matrix.ghc_version }}
3640 cabal-version: "3.10.1.0"
@@ -66,7 +70,7 @@ jobs:
6670 if: github.event_name == 'release'
6771 steps:
6872 - uses: actions/checkout@v3
69− - uses: haskell/actions/setup@v2
73+ - uses: haskell-actions/setup@v2
7074 with:
7175 cabal-version: "3.10.1.0"
7276 - name: Install C++ library
@@ -81,11 +85,11 @@ jobs:
8185 run: |
8286 cabal haddock --builddir "$GITHUB_WORKSPACE/doc" --haddock-for-hackage --enable-doc
8387 echo "docs=$(find "$GITHUB_WORKSPACE/doc" -maxdepth 1 -type f -name '*-docs.tar.gz')" >> "$GITHUB_ENV"
84− - uses: actions/upload-artifact@v2
88+ - uses: actions/upload-artifact@v6
8589 with:
8690 name: Source tarball
8791 path: ${{ env.dist }}
88− - uses: svenstaro/upload-release-action@2.2.1
92+ - uses: svenstaro/upload-release-action@2.11.3
8993 with:
9094 repo_token: ${{ secrets.GITHUB_TOKEN }}
9195 file: ${{ env.dist }}
LICENSE+1−1
@@ -1,6 +1,6 @@
11MIT License
22
3−Copyright (c) 2021 Typeable
3+Copyright (c) 2023 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+6−4
@@ -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" PhoneNumber *c_phone_number_marshal(phone_number const *c_number)
58+extern "C" CxxPhoneNumber *c_phone_number_marshal(phone_number const *c_number)
5959{
6060 PhoneNumber *number = new PhoneNumber();
6161 if (c_number->extension != nullptr)
@@ -72,11 +72,12 @@ extern "C" PhoneNumber *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 number;
75+ return reinterpret_cast<CxxPhoneNumber *>(number);
7676}
7777
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)
7979{
80+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
8081 if (number->has_extension())
8182 unmarshal_string_size(number->extension(), c_number->extension, c_number->extension_size);
8283 else
@@ -99,7 +100,8 @@ extern "C" void c_phone_number_unmarshal(PhoneNumber const *number, phone_number
99100 c_number->number_of_leading_zeros = number->number_of_leading_zeros();
100101}
101102
102−extern "C" void c_phone_number_free(PhoneNumber *number)
103+extern "C" void c_phone_number_free(CxxPhoneNumber *ptr)
103104{
105+ auto number = reinterpret_cast<PhoneNumber *>(ptr);
104106 delete number;
105107}
cxxbits/c_phonenumberutil.cpp+45−26
@@ -310,10 +310,11 @@ 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− PhoneNumber const *number,
313+ CxxPhoneNumber const *ptr,
314314 c_string *c_nsn
315315)
316316{
317+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
317318 std::string nsn;
318319 PhoneNumberUtil::GetInstance()->GetNationalSignificantNumber(*number, &nsn);
319320 unmarshal_c_string(nsn, *c_nsn);
@@ -330,23 +331,25 @@ extern "C" void c_phone_number_util_get_country_mobile_token(
330331}
331332
332333extern "C" void c_phone_number_util_format(
333− PhoneNumber const *number,
334+ CxxPhoneNumber const *ptr,
334335 phone_number_format format,
335336 c_string *c_string
336337)
337338{
339+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
338340 std::string string;
339341 PhoneNumberUtil::GetInstance()->Format(*number, marshal_phone_number_format(format), &string);
340342 unmarshal_c_string(string, *c_string);
341343}
342344
343345extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
344− PhoneNumber const *number,
346+ CxxPhoneNumber const *ptr,
345347 char const *c_carrier_code,
346348 size_t c_carrier_code_size,
347349 c_string *c_string
348350)
349351{
352+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
350353 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
351354 std::string string;
352355 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithCarrierCode(*number, carrier_code, &string);
@@ -354,12 +357,13 @@ extern "C" void c_phone_number_util_format_national_number_with_carrier_code(
354357}
355358
356359extern "C" void c_phone_number_util_format_national_number_with_preferred_carrier_code(
357− PhoneNumber const *number,
360+ CxxPhoneNumber const *ptr,
358361 char const *c_carrier_code,
359362 size_t c_carrier_code_size,
360363 c_string *c_string
361364)
362365{
366+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
363367 std::string const carrier_code(c_carrier_code, c_carrier_code_size);
364368 std::string string;
365369 PhoneNumberUtil::GetInstance()->FormatNationalNumberWithPreferredCarrierCode(*number, carrier_code, &string);
@@ -367,13 +371,14 @@ extern "C" void c_phone_number_util_format_national_number_with_preferred_carrie
367371}
368372
369373extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
370− PhoneNumber const *number,
374+ CxxPhoneNumber const *ptr,
371375 char const *c_region,
372376 size_t c_region_size,
373377 int with_formatting,
374378 c_string *c_string
375379)
376380{
381+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
377382 std::string const region(c_region, c_region_size);
378383 std::string string;
379384 PhoneNumberUtil::GetInstance()->FormatNumberForMobileDialing(*number, region, with_formatting, &string);
@@ -381,12 +386,13 @@ extern "C" void c_phone_number_util_format_number_for_mobile_dialing(
381386}
382387
383388extern "C" void c_phone_number_util_format_out_of_country_calling_number(
384− PhoneNumber const *number,
389+ CxxPhoneNumber const *ptr,
385390 char const *c_region,
386391 size_t c_region_size,
387392 c_string *c_string
388393)
389394{
395+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
390396 std::string const region(c_region, c_region_size);
391397 std::string string;
392398 PhoneNumberUtil::GetInstance()->FormatOutOfCountryCallingNumber(*number, region, &string);
@@ -394,12 +400,13 @@ extern "C" void c_phone_number_util_format_out_of_country_calling_number(
394400}
395401
396402extern "C" void c_phone_number_util_format_in_original_format(
397− PhoneNumber const *number,
403+ CxxPhoneNumber const *ptr,
398404 char const *c_region,
399405 size_t c_region_size,
400406 c_string *c_string
401407)
402408{
409+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
403410 std::string const region(c_region, c_region_size);
404411 std::string string;
405412 PhoneNumberUtil::GetInstance()->FormatInOriginalFormat(*number, region, &string);
@@ -407,24 +414,26 @@ extern "C" void c_phone_number_util_format_in_original_format(
407414}
408415
409416extern "C" void c_phone_number_util_format_out_of_country_keeping_alpha_chars(
410− PhoneNumber const *number,
417+ CxxPhoneNumber const *ptr,
411418 char const *c_region,
412419 size_t c_region_size,
413420 c_string *c_string
414421)
415422{
423+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
416424 std::string const region(c_region, c_region_size);
417425 std::string string;
418426 PhoneNumberUtil::GetInstance()->FormatOutOfCountryKeepingAlphaChars(*number, region, &string);
419427 unmarshal_c_string(string, *c_string);
420428}
421429
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)
423431{
432+ auto input = reinterpret_cast<PhoneNumber const *>(ptr);
424433 auto *output = new PhoneNumber(*input);
425434 if (PhoneNumberUtil::GetInstance()->TruncateTooLongNumber(output))
426435 {
427− return output;
436+ return reinterpret_cast<CxxPhoneNumber *>(output);
428437 }
429438 else
430439 {
@@ -433,33 +442,37 @@ extern "C" PhoneNumber *c_phone_number_util_truncate_too_long_number(PhoneNumber
433442 }
434443}
435444
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)
437446{
447+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
438448 return unmarshal_phone_number_type(
439449 PhoneNumberUtil::GetInstance()->GetNumberType(*number)
440450 );
441451}
442452
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)
444454{
455+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
445456 return PhoneNumberUtil::GetInstance()->IsValidNumber(*number);
446457}
447458
448459extern "C" int c_phone_number_util_is_valid_number_for_region(
449− PhoneNumber const *number,
460+ CxxPhoneNumber const *ptr,
450461 char const *c_region,
451462 size_t c_region_size
452463)
453464{
465+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
454466 std::string const region(c_region, c_region_size);
455467 return PhoneNumberUtil::GetInstance()->IsValidNumberForRegion(*number, region);
456468}
457469
458470extern "C" void c_phone_number_util_get_region_code_for_number(
459− PhoneNumber const *number,
471+ CxxPhoneNumber const *ptr,
460472 c_string *c_region
461473)
462474{
475+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
463476 std::string region;
464477 PhoneNumberUtil::GetInstance()->GetRegionCodeForNumber(*number, &region);
465478 unmarshal_c_string(region, *c_region);
@@ -518,10 +531,11 @@ extern "C" void c_phone_number_util_get_ndd_prefix_for_region(
518531}
519532
520533extern "C" validation_result c_phone_number_util_is_possible_number_for_type_with_reason(
521− PhoneNumber const *number,
534+ CxxPhoneNumber const *ptr,
522535 phone_number_type ntype
523536)
524537{
538+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
525539 return unmarshal_validation_result(
526540 PhoneNumberUtil::GetInstance()->IsPossibleNumberForTypeWithReason(
527541 *number,
@@ -530,13 +544,15 @@ extern "C" validation_result c_phone_number_util_is_possible_number_for_type_wit
530544 );
531545}
532546
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)
534548{
549+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
535550 return PhoneNumberUtil::GetInstance()->CanBeInternationallyDialled(*number);
536551}
537552
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)
539554{
555+ auto number = reinterpret_cast<PhoneNumber const *>(ptr);
540556 return PhoneNumberUtil::GetInstance()->IsNumberGeographical(*number);
541557}
542558
@@ -556,14 +572,14 @@ extern "C" error_type c_phone_number_util_parse(
556572 size_t c_string_size,
557573 char const *c_region,
558574 size_t c_region_size,
559− PhoneNumber **number
575+ CxxPhoneNumber **number
560576)
561577{
562578 std::string const string(c_string, c_string_size);
563579 std::string const region(c_region, c_region_size);
564− *number = new PhoneNumber();
580+ *number = reinterpret_cast<CxxPhoneNumber *>(new PhoneNumber());
565581 return unmarshal_error_type(
566− PhoneNumberUtil::GetInstance()->Parse(string, region, *number)
582+ PhoneNumberUtil::GetInstance()->Parse(string, region, reinterpret_cast<PhoneNumber *>(*number))
567583 );
568584}
569585
@@ -572,22 +588,24 @@ extern "C" error_type c_phone_number_util_parse_and_keep_raw_input(
572588 size_t c_string_size,
573589 char const *c_region,
574590 size_t c_region_size,
575− PhoneNumber **number
591+ CxxPhoneNumber **number
576592)
577593{
578594 std::string const string(c_string, c_string_size);
579595 std::string const region(c_region, c_region_size);
580− *number = new PhoneNumber();
596+ *number = reinterpret_cast<CxxPhoneNumber *>(new PhoneNumber());
581597 return unmarshal_error_type(
582− PhoneNumberUtil::GetInstance()->ParseAndKeepRawInput(string, region, *number)
598+ PhoneNumberUtil::GetInstance()->ParseAndKeepRawInput(string, region, reinterpret_cast<PhoneNumber *>(*number))
583599 );
584600}
585601
586602extern "C" match_type c_phone_number_util_is_number_match(
587− PhoneNumber const *number1,
588− PhoneNumber const *number2
603+ CxxPhoneNumber const *ptr1,
604+ CxxPhoneNumber const *ptr2
589605)
590606{
607+ auto number1 = reinterpret_cast<PhoneNumber const *>(ptr1);
608+ auto number2 = reinterpret_cast<PhoneNumber const *>(ptr2);
591609 return unmarshal_match_type(
592610 PhoneNumberUtil::GetInstance()->IsNumberMatch(*number1, *number2)
593611 );
@@ -608,11 +626,12 @@ extern "C" match_type c_phone_number_util_is_number_match_with_two_strings(
608626}
609627
610628extern "C" match_type c_phone_number_util_is_number_match_with_one_string(
611− PhoneNumber const *number1,
629+ CxxPhoneNumber const *ptr1,
612630 char const *c_number2,
613631 size_t c_number2_size
614632)
615633{
634+ auto number1 = reinterpret_cast<PhoneNumber const *>(ptr1);
616635 std::string const number2(c_number2, c_number2_size);
617636 return unmarshal_match_type(
618637 PhoneNumberUtil::GetInstance()->IsNumberMatchWithOneString(*number1, number2)
include/c_phonenumber.h+4−8
@@ -43,20 +43,16 @@ typedef struct
4343 char has_number_of_leading_zeros;
4444} phone_number;
4545
46−#ifdef __cplusplus
47−typedef i18n::phonenumbers::PhoneNumber PhoneNumber;
48−#else
49−typedef struct PhoneNumber PhoneNumber;
50−#endif
46+struct CxxPhoneNumber;
5147
5248// The returned object is allocated by `new` and managed by C++ RAII, and it is
5349// 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 *);
5551
5652// phone_number * points to an area which will be filled with the data of the
5753// given PhoneNumber.
58−void c_phone_number_unmarshal(PhoneNumber const *, phone_number *);
54+void c_phone_number_unmarshal(struct CxxPhoneNumber const *, phone_number *);
5955
60−void c_phone_number_free(PhoneNumber *);
56+void c_phone_number_free(struct CxxPhoneNumber *);
6157
6258#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(PhoneNumber const *, c_string *);
100+void c_phone_number_util_get_national_significant_number(struct CxxPhoneNumber const *, c_string *);
101101void 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 *);
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 *);
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 *);
109109// /!\ May return NULL
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 *);
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 *);
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(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 *);
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 *);
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, 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 *);
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 *);
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(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);
129129
130130#endif
include/common.h+3−2
@@ -4,6 +4,7 @@
44#include <cstddef>
55#include <cstring>
66#include <type_traits>
7+#include <utility>
78
89// Given `enum T { A, B, C }` and `enum S { X, Y, Z }`, we can use
910// `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
3132
3233template<typename T, T... TVals, typename S, S... SVals>
3334struct 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<
3536 std::integer_sequence<
3637 typename std::common_type<
3738 typename std::underlying_type<T>::type,
@@ -46,7 +47,7 @@ struct is_same_enum<enum_values<T, TVals...>, enum_values<S, SVals...>>:
4647 >::type,
4748 SVals...
4849 >
49− >>
50+ >::value>
5051{};
5152
5253inline void unmarshal_string_size(std::string const &string, char *&c_string, size_t &c_string_size)
libphonenumber.cabal+18−13
@@ -1,6 +1,6 @@
11cabal-version: 3.0
22name: libphonenumber
3−version: 0.0.0.0
3+version: 0.1.4.0
44category: Data
55synopsis: Parsing, formatting, and validating international phone
66 numbers
@@ -8,7 +8,8 @@ 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@.
11+ and @ShortNumberInfo@. The C++ library must be of version
12+ >= 8.7.0.
1213
1314 The interface largely resembles that of the original unified
1415 C++, Java, and JavaScript version of the library, with some
@@ -24,7 +25,7 @@ description:
2425 and to avoid a dependency on @text@, we use 'ByteString'
2526 throughout the library instead of 'Data.Text.Text'.
2627
27−copyright: 2023 Typeable
28+copyright: 2023-2025 Typeable
2829author: Typeable
2930maintainer: mniip@typeable.io
3031homepage: https://github.com/typeable/libphonenumber/
@@ -36,9 +37,13 @@ tested-with:
3637 , GHC == 8.8.4
3738 , GHC == 8.10.7
3839 , GHC == 9.0.2
39− , GHC == 9.2.7
40− , GHC == 9.4.4
41− , GHC == 9.6.1
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
4247
4348build-type: Simple
4449
@@ -59,12 +64,13 @@ library
5964 , Data.PhoneNumber.Internal.Number
6065 , Data.PhoneNumber.Internal.Util
6166 build-depends:
62− , base >= 4.12 && < 4.19
63− , bytestring >= 0.10.8 && < 0.12
64− , containers >= 0.6.0 && < 0.7
65− , deepseq >= 1.4.4 && < 1.5
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
6671 , transformers >= 0.5.5 && < 0.7
6772 build-tool-depends: c2hs:c2hs
73+ pkgconfig-depends: protobuf
6874 include-dirs: include
6975 includes:
7076 , c_phonenumber.h
@@ -74,7 +80,6 @@ library
7480 , cxxbits/c_phonenumberutil.cpp
7581 extra-libraries:
7682 , phonenumber
77− , protobuf
7883 if impl(ghc >= 9.4)
7984 build-depends: system-cxx-std-lib
8085 else
@@ -104,9 +109,9 @@ test-suite spec_test
104109 , base
105110 , bytestring
106111 , containers
107− , hspec >= 2.10.8 && < 2.11
112+ , hspec >= 2.10.8 && < 2.12
108113 , libphonenumber
109− , QuickCheck >= 2.13.1 && < 2.15
114+ , QuickCheck >= 2.13.1 && < 2.16
110115 main-is: Spec.hs
111116 hs-source-dirs: test
112117 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 *PhoneNumber foreign finalizer c_phone_number_free newtype#}
129+{#pointer *CxxPhoneNumber as PhoneNumber foreign finalizer c_phone_number_free newtype#}
130130
131131{#fun unsafe c_phone_number_marshal
132132 { withCPhoneNumber* `CPhoneNumber'
src/Data/PhoneNumber/Number.hs+69−10
@@ -21,16 +21,10 @@ module Data.PhoneNumber.Number
2121 ) where
2222
2323import Data.ByteString (ByteString)
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 )
24+import Data.PhoneNumber.Internal.Number
25+ ( CPhoneNumber(CPhoneNumber), PhoneNumber, CountryCodeSource, toCPhoneNumber
26+ , fromCPhoneNumber
27+ )
3428import qualified Data.PhoneNumber.Internal.Number as I
3529
3630-- | A country calling code (International Subscriber Dialing code, ISD code),
@@ -79,3 +73,68 @@ pattern PhoneNumber
7973 = fromCPhoneNumber $ CPhoneNumber{..}
8074
8175{-# 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 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.
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.
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+24−23
@@ -53,11 +53,13 @@ data ParsedNumber = ParsedNumber (ParseMode, Maybe Region, ParserInput) PhoneNum
5353 deriving stock (Show)
5454
5555instance Arbitrary ParsedNumber where
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
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
6163 shrink (ParsedNumber (mode, region, input) _) = do
6264 ParserInput input' <- shrink input
6365 case parseNumber mode region input' of
@@ -113,7 +115,7 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
113115 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
114116 describe "Dialable" $ do
115117 -- PhoneNumberUtil::NormalizeDiallableCharsOnly will error on any invalid UTF8
116− xprop "doesn't randomly fail" $ \str ->
118+ prop "doesn't randomly fail" $ \str ->
117119 not (BS.null $ normalizeNumber Digits $ "0" <> BS.pack str)
118120 .&&. not (BS.null $ normalizeNumber Digits $ BS.pack str <> "0")
119121
@@ -123,15 +125,9 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
123125 prop "returns only ASCII digits" $ \(ParsedNumber _ pn) ->
124126 BSC.all (`elem` ['0'..'9']) $ nationalSignificantNumber pn
125127 modifyMaxDiscardRatio (* 10) $ do
126− prop "concatenated with country code parses to the original (if valid and not MX)" $
127− \(ParsedNumber (_, mReg, 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− mReg == Just "MX" && "11" `BS.isPrefixOf` normalizeNumber Digits input
133− then discard
134− else isValidNumber Nothing pn ==>
128+ prop "concatenated with country code parses to the original (if valid)" $
129+ \(ParsedNumber _ pn) ->
130+ isValidNumber Nothing pn ==>
135131 let
136132 cc = countryCode pn
137133 nsn = nationalSignificantNumber pn
@@ -155,14 +151,19 @@ main = hspec $ modifyMaxSuccess (* 10) $ do
155151 extension pn == Nothing ==>
156152 isRight $ parseNumber Canonicalize Nothing
157153 $ formatNumber International pn
158− prop "with E164 produces a parseable result" $
159− \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
160− isRight $ parseNumber Canonicalize Nothing
161− $ formatNumber E164 pn
162− prop "with RFC3966 produces a parseable result" $
163− \(ParsedNumber _ pn) -> possibleNumber Unknown pn == IsPossible ==>
164− isRight $ parseNumber Canonicalize Nothing
165− $ formatNumber RFC3966 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
166167
167168 describe "truncateTooLongNumber" $ do
168169 pure ()