use crate::{
ibig::IBig,
radix::{self, is_radix_valid, Digit},
ubig::UBig,
Sign::*,
};
use core::str::FromStr;
use dashu_base::ParseError;
mod non_power_two;
mod power_two;
impl FromStr for UBig {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<UBig, ParseError> {
UBig::from_str_radix(s, 10)
}
}
impl FromStr for IBig {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<IBig, ParseError> {
IBig::from_str_radix(s, 10)
}
}
impl UBig {
pub fn from_str_radix(src: &str, radix: u32) -> Result<UBig, ParseError> {
let radix = u8::try_from(radix).map_err(|_| ParseError::UnsupportedRadix)?;
if !is_radix_valid(radix) {
return Err(ParseError::UnsupportedRadix);
}
let src = src.strip_prefix('+').unwrap_or(src);
UBig::from_str_radix_no_sign(src, radix)
}
#[inline]
pub fn from_str_with_radix_prefix(src: &str) -> Result<(UBig, Digit), ParseError> {
UBig::from_str_with_radix_default(src, 10)
}
#[inline]
pub fn from_str_with_radix_default(
src: &str,
default_radix: Digit,
) -> Result<(UBig, Digit), ParseError> {
let src = src.strip_prefix('+').unwrap_or(src);
UBig::from_str_with_radix_prefix_no_sign(src, default_radix)
}
fn from_str_with_radix_prefix_no_sign(
src: &str,
default_radix: Digit,
) -> Result<(UBig, Digit), ParseError> {
if let Some(bin) = src.strip_prefix("0b") {
UBig::from_str_radix_no_sign(bin, 2).map(|v| (v, 2))
} else if let Some(oct) = src.strip_prefix("0o") {
UBig::from_str_radix_no_sign(oct, 8).map(|v| (v, 8))
} else if let Some(hex) = src.strip_prefix("0x") {
UBig::from_str_radix_no_sign(hex, 16).map(|v| (v, 16))
} else {
UBig::from_str_radix_no_sign(src, default_radix).map(|v| (v, default_radix))
}
}
fn from_str_radix_no_sign(mut src: &str, radix: Digit) -> Result<UBig, ParseError> {
debug_assert!(radix::is_radix_valid(radix));
if src.is_empty() {
return Err(ParseError::NoDigits);
}
while let Some(src2) = src.strip_prefix('0') {
src = src2;
}
if radix.is_power_of_two() {
power_two::parse(src, radix)
} else {
non_power_two::parse(src, radix)
}
}
}
impl IBig {
pub fn from_str_radix(mut src: &str, radix: u32) -> Result<IBig, ParseError> {
let radix = u8::try_from(radix).map_err(|_| ParseError::UnsupportedRadix)?;
if !is_radix_valid(radix) {
return Err(ParseError::UnsupportedRadix);
}
let sign = match src.strip_prefix('-') {
Some(s) => {
src = s;
Negative
}
None => {
src = src.strip_prefix('+').unwrap_or(src);
Positive
}
};
let mag = UBig::from_str_radix_no_sign(src, radix)?;
Ok(IBig(mag.0.with_sign(sign)))
}
pub fn from_str_with_radix_prefix(src: &str) -> Result<(IBig, Digit), ParseError> {
IBig::from_str_with_radix_default(src, 10)
}
#[inline]
pub fn from_str_with_radix_default(
src: &str,
default_radix: Digit,
) -> Result<(IBig, Digit), ParseError> {
let (src, sign) = match src.strip_prefix('-') {
Some(s) => (s, Negative),
None => (src.strip_prefix('+').unwrap_or(src), Positive),
};
let (mag, radix) = UBig::from_str_with_radix_prefix_no_sign(src, default_radix)?;
Ok((IBig(mag.0.with_sign(sign)), radix))
}
}