1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

//! [`icu_decimal`](crate) offers localized decimal number formatting.
//!
//! Currently, [`icu_decimal`](crate) provides [`FixedDecimalFormat`], which renders basic decimal numbers
//! in a locale-sensitive way.
//!
//! Support for currencies, measurement units, and compact notation is planned. To track progress,
//! follow this issue:
//!
//! https://github.com/unicode-org/icu4x/issues/275
//!
//! # Examples
//!
//! ## Format a number with Bengali digits
//!
//! ```
//! use icu::decimal::FixedDecimalFormat;
//! use icu::locid::Locale;
//! use icu::locid::macros::langid;
//! use writeable::Writeable;
//!
//! let locale: Locale = langid!("bn").into();
//! let provider = icu_testdata::get_provider();
//! let fdf = FixedDecimalFormat::try_new(locale, &provider, Default::default())
//!     .expect("Data should load successfully");
//!
//! let fixed_decimal = 1000007.into();
//! let formatted_value = fdf.format(&fixed_decimal);
//! let formatted_str = formatted_value.writeable_to_string();
//!
//! assert_eq!("১০,০০,০০৭", formatted_str);
//! ```
//!
//! ## Format a number with digits after the decimal separator
//!
//! ```
//! use fixed_decimal::FixedDecimal;
//! use icu::decimal::FixedDecimalFormat;
//! use icu::locid::Locale;
//! use writeable::Writeable;
//!
//! let locale = Locale::und();
//! let provider = icu_provider::inv::InvariantDataProvider;
//! let fdf = FixedDecimalFormat::try_new(locale, &provider, Default::default())
//!     .expect("Data should load successfully");
//!
//! let fixed_decimal = FixedDecimal::from(200050)
//!     .multiplied_pow10(-2)
//!     .expect("Operation is fully in range");
//!
//! assert_eq!("2,000.50", fdf.format(&fixed_decimal).writeable_to_string());
//! ```
//!
//! [`FixedDecimalFormat`]: FixedDecimalFormat

#![cfg_attr(not(any(test, feature = "std")), no_std)]

extern crate alloc;

pub mod error;
pub mod format;
mod grouper;
pub mod options;
pub mod provider;
mod sign_selector;

pub use error::Error as FixedDecimalFormatError;
pub use format::FormattedFixedDecimal;

use fixed_decimal::FixedDecimal;
use icu_locid::Locale;
use icu_provider::prelude::*;

/// A formatter for [`FixedDecimal`], rendering decimal digits in an i18n-friendly way.
///
/// [`FixedDecimalFormat`] supports:
///
/// 1. Rendering in the local numbering system
/// 2. Locale-sensitive grouping separator positions
/// 3. Locale-sensitive plus and minus signs
///
/// Read more about the options in the [`options`] module.
///
/// See the crate-level documentation for examples.
pub struct FixedDecimalFormat<'data> {
    options: options::FixedDecimalFormatOptions,
    symbols: DataPayload<'data, provider::DecimalSymbolsV1Marker>,
}

impl<'data> FixedDecimalFormat<'data> {
    /// Creates a new [`FixedDecimalFormat`] from locale data and an options bag.
    pub fn try_new<
        T: Into<Locale>,
        D: DataProvider<'data, provider::DecimalSymbolsV1Marker> + ?Sized,
    >(
        locale: T,
        data_provider: &D,
        options: options::FixedDecimalFormatOptions,
    ) -> Result<Self, FixedDecimalFormatError> {
        let symbols = data_provider
            .load_payload(&DataRequest {
                resource_path: ResourcePath {
                    key: provider::key::SYMBOLS_V1,
                    options: ResourceOptions {
                        variant: None,
                        langid: Some(locale.into().into()),
                    },
                },
            })?
            .take_payload()?;
        Ok(Self { options, symbols })
    }

    /// Formats a [`FixedDecimal`], returning a [`FormattedFixedDecimal`].
    pub fn format<'l>(&'l self, value: &'l FixedDecimal) -> FormattedFixedDecimal<'l> {
        FormattedFixedDecimal {
            value,
            options: &self.options,
            symbols: self.symbols.get(),
        }
    }
}