mirror of
https://github.com/powdr-labs/powdr.git
synced 2026-04-20 03:03:25 -04:00
Make conversions safer.
This commit is contained in:
@@ -253,6 +253,18 @@ macro_rules! powdr_field {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for $name {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let n = BigUint::from_str(s).map_err(|e| e.to_string())?;
|
||||
if n >= <$ark_type>::MODULUS.into() {
|
||||
Err(format!("Decimal number \"{s}\" too large for field."))
|
||||
} else {
|
||||
Ok(n.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::LowerHex for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::LowerHex::fmt(&self.to_integer(), f)
|
||||
@@ -267,16 +279,13 @@ macro_rules! powdr_field {
|
||||
Some(KnownField::$name)
|
||||
}
|
||||
|
||||
fn from_str(s: &str) -> Self {
|
||||
Self {
|
||||
value: <$ark_type>::from_str(s).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_str_radix(s: &str, radix: u32) -> Result<Self, String> {
|
||||
BigUint::from_str_radix(s, radix)
|
||||
.map(|n| n.into())
|
||||
.map_err(|e| e.to_string())
|
||||
let n = BigUint::from_str_radix(s, radix).map_err(|e| e.to_string())?;
|
||||
if n >= <$ark_type>::MODULUS.into() {
|
||||
Err(format!("Hexadecimal number \"0x{s}\" too large for field."))
|
||||
} else {
|
||||
Ok(n.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn to_degree(&self) -> DegreeType {
|
||||
|
||||
@@ -68,9 +68,9 @@ pub fn read_polys_csv_file<T: FieldElement>(file: &mut impl Read) -> Vec<(String
|
||||
let value = if let Some(value) = value.strip_prefix("0x") {
|
||||
T::from_str_radix(value, 16).unwrap()
|
||||
} else if let Some(value) = value.strip_prefix('-') {
|
||||
-T::from_str(value)
|
||||
-T::from_str(value).unwrap()
|
||||
} else {
|
||||
T::from_str(value)
|
||||
T::from_str(value).unwrap()
|
||||
};
|
||||
polys[idx].1.push(value);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{fmt, hash::Hash, ops::*};
|
||||
use std::{fmt, hash::Hash, ops::*, str::FromStr};
|
||||
|
||||
use num_traits::{One, Zero};
|
||||
|
||||
@@ -78,6 +78,7 @@ pub trait FieldElement:
|
||||
+ fmt::Debug
|
||||
+ From<Self::Integer>
|
||||
+ From<num_bigint::BigUint>
|
||||
+ FromStr<Err = String>
|
||||
+ From<u32>
|
||||
+ From<u64>
|
||||
+ From<i32>
|
||||
@@ -110,8 +111,6 @@ pub trait FieldElement:
|
||||
|
||||
fn from_bytes_le(bytes: &[u8]) -> Self;
|
||||
|
||||
fn from_str(s: &str) -> Self;
|
||||
|
||||
fn from_str_radix(s: &str, radix: u32) -> Result<Self, String>;
|
||||
|
||||
/// Returns true if the value is in the "lower half" of the field,
|
||||
|
||||
@@ -576,7 +576,7 @@ PublicIdentifier: String = {
|
||||
}
|
||||
|
||||
FieldElement: T = {
|
||||
r"[0-9][0-9_]*" => T::from_str(&<>.replace('_', "")),
|
||||
r"[0-9][0-9_]*" => T::from_str(&<>.replace('_', "")).unwrap(),
|
||||
r"0x[0-9A-Fa-f][0-9A-Fa-f_]*" => T::from_str_radix(&<>[2..].replace('_', ""), 16).unwrap(),
|
||||
}
|
||||
|
||||
|
||||
@@ -591,4 +591,28 @@ mod test {
|
||||
"#;
|
||||
parse_and_evaluate_symbol(src, "F.x");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = r#"Hexadecimal number \"0x9999999999999999999999999999999\" too large for field"#]
|
||||
pub fn hex_number_outside_field() {
|
||||
// This tests that the parser does not lose precision when parsing large integers.
|
||||
// We are currently going through FieldElements in the parser, which have limited precision.
|
||||
// As soon as we use Integers there, this test should succeed.
|
||||
let src = r#"
|
||||
let N = 0x9999999999999999999999999999999;
|
||||
"#;
|
||||
parse_and_evaluate_symbol(src, "N");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = r#"Decimal number \"9999999999999999999999999999999\" too large for field"#]
|
||||
pub fn decimal_number_outside_field() {
|
||||
// This tests that the parser does not lose precision when parsing large integers.
|
||||
// We are currently going through FieldElements in the parser, which have limited precision.
|
||||
// As soon as we use Integers there, this test should succeed.
|
||||
let src = r#"
|
||||
let N = 9999999999999999999999999999999;
|
||||
"#;
|
||||
parse_and_evaluate_symbol(src, "N");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ pub fn inputs_to_query_callback<T: FieldElement>(inputs: Vec<T>) -> impl QueryCa
|
||||
// called again.
|
||||
Ok(Some(0.into()))
|
||||
}
|
||||
["\"hint\"", value] => Ok(Some(T::from_str(value))),
|
||||
["\"hint\"", value] => Ok(Some(T::from_str(value).unwrap())),
|
||||
k => Err(format!("Unsupported query: {}", k.iter().format(", "))),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user