Skip to content

Commit b6bc84f

Browse files
author
lcnbr
committed
use a bincode PR to implement derived Encode and Decode with StateMap as context
1 parent eaa15a6 commit b6bc84f

12 files changed

+357
-10
lines changed

Cargo.toml

+18-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ inherits = "dev"
2121
opt-level = 3
2222

2323
[lib]
24-
crate-type = ["lib"]
24+
crate-type = ["lib", "cdylib"]
2525
name = "symbolica"
2626

2727
[features]
@@ -32,25 +32,28 @@ faster_alloc = ["tikv-jemallocator"]
3232
# sort functions based on an argument-by-argument comparison
3333
full_fn_cmp = []
3434
mathematica_api = ["wolfram-library-link"]
35-
python_api = ["pyo3", "bincode"]
35+
python_api = ["pyo3"]
3636
# do not create a Python module but allow other crates to do so
3737
python_no_module = ["python_api"]
3838
# build a module that is independent of the specific Python version
3939
python_abi3 = ["pyo3/abi3", "pyo3/abi3-py37"]
4040
tracing_only_warnings = ["tracing/release_max_level_warn"]
41+
# bincode = ["dep:bincode"]
4142

4243
[dependencies.pyo3]
4344
features = ["extension-module", "abi3", "py-clone"]
4445
optional = true
4546
version = "0.22"
4647

4748
[dev-dependencies]
48-
tracing-subscriber = {version = "0.3.18", features = ["env-filter"]}
49+
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
4950

5051
[dependencies]
5152
ahash = "0.8.7"
5253
append-only-vec = "0.1"
53-
bincode = {version = "1.3", optional = true}
54+
bincode = { git = "https://github.com/branchseer/bincode", branch = "decode_context", features = [
55+
"serde",
56+
] }
5457
brotli = "5.0"
5558
byteorder = "1.5"
5659
bytes = "1.5"
@@ -63,11 +66,19 @@ rand_xoshiro = "0.6"
6366
rayon = "1.8"
6467
rug = "=1.25.0"
6568
self_cell = "1.0"
66-
serde = {version = "1.0", features = ["derive"]}
69+
serde = { version = "1.0", features = ["derive"] }
6770
smallvec = "1.13"
6871
smartstring = "1.0"
69-
tikv-jemallocator = {version = "0.5.4", optional = true}
72+
tikv-jemallocator = { version = "0.5.4", optional = true }
7073
tinyjson = "2.5"
7174
tracing = "0.1"
7275
wide = "0.7"
73-
wolfram-library-link = {version = "0.2.9", optional = true}
76+
wolfram-library-link = { version = "0.2.9", optional = true }
77+
78+
79+
[build-dependencies]
80+
pyo3-build-config = "*"
81+
82+
83+
[patch.crates-io]
84+
bincode = { git = "https://github.com/branchseer/bincode", branch = "decode_context" }

build.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use std::process::Command;
22
fn main() {
3+
if cfg!(target_os = "macos") {
4+
pyo3_build_config::add_extension_module_link_args();
5+
println!("cargo:rustc-link-lib=gcc_s");
6+
}
37
let output = Command::new("git")
48
.args(["describe", "--tags"])
59
.output()

patch_symbolica.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../bin/patch_symbolica.py

src/atom.rs

+45
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod coefficient;
22
mod core;
33
pub mod representation;
44

5+
use bincode::{de::read::Reader, enc::write::Writer, Decode, Encode};
56
use representation::InlineVar;
67

78
use crate::{
@@ -20,6 +21,7 @@ pub use self::representation::{
2021
};
2122
use self::representation::{FunView, RawAtom};
2223

24+
use std::result;
2325
/// A symbol, for example the name of a variable or the name of a function,
2426
/// together with its properties.
2527
/// Should be created using [State::get_symbol].
@@ -33,6 +35,49 @@ pub struct Symbol {
3335
is_linear: bool,
3436
}
3537

38+
impl<__Context> ::bincode::Decode<__Context> for Symbol {
39+
fn decode<__D: ::bincode::de::Decoder<Context = __Context>>(
40+
decoder: &mut __D,
41+
) -> Result<Self, ::bincode::error::DecodeError> {
42+
Ok(Self {
43+
id: ::bincode::Decode::decode(decoder)?,
44+
wildcard_level: ::bincode::Decode::decode(decoder)?,
45+
is_symmetric: ::bincode::Decode::decode(decoder)?,
46+
is_antisymmetric: ::bincode::Decode::decode(decoder)?,
47+
is_cyclesymmetric: ::bincode::Decode::decode(decoder)?,
48+
is_linear: ::bincode::Decode::decode(decoder)?,
49+
})
50+
}
51+
}
52+
impl<'__de, __Context> ::bincode::BorrowDecode<'__de, __Context> for Symbol {
53+
fn borrow_decode<__D: ::bincode::de::BorrowDecoder<'__de, Context = __Context>>(
54+
decoder: &mut __D,
55+
) -> Result<Self, ::bincode::error::DecodeError> {
56+
Ok(Self {
57+
id: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
58+
wildcard_level: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
59+
is_symmetric: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
60+
is_antisymmetric: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
61+
is_cyclesymmetric: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
62+
is_linear: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
63+
})
64+
}
65+
}
66+
67+
impl ::bincode::Encode for Symbol {
68+
fn encode<__E: ::bincode::enc::Encoder>(
69+
&self,
70+
encoder: &mut __E,
71+
) -> Result<(), ::bincode::error::EncodeError> {
72+
::bincode::Encode::encode(&self.id, encoder)?;
73+
::bincode::Encode::encode(&self.wildcard_level, encoder)?;
74+
::bincode::Encode::encode(&self.is_symmetric, encoder)?;
75+
::bincode::Encode::encode(&self.is_antisymmetric, encoder)?;
76+
::bincode::Encode::encode(&self.is_cyclesymmetric, encoder)?;
77+
::bincode::Encode::encode(&self.is_linear, encoder)?;
78+
Ok(())
79+
}
80+
}
3681
impl std::fmt::Debug for Symbol {
3782
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3883
f.write_fmt(format_args!("{}", self.id))?;

src/atom/representation.rs

+76-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
use bincode::{
2+
de::read::Reader, enc::write::Writer, impl_borrow_decode_with_context, BorrowDecode, Decode,
3+
Encode,
4+
};
15
use byteorder::{LittleEndian, WriteBytesExt};
26
use bytes::{Buf, BufMut};
37
use smartstring::alias::String;
48
use std::{
59
borrow::Borrow,
610
cmp::Ordering,
711
hash::Hash,
8-
io::{Read, Write},
12+
io::{Cursor, Read, Write},
913
};
1014

1115
use crate::{
@@ -157,6 +161,77 @@ impl InlineNum {
157161
}
158162
}
159163

164+
impl Encode for Atom {
165+
fn encode<E: bincode::enc::Encoder>(
166+
&self,
167+
encoder: &mut E,
168+
) -> Result<(), bincode::error::EncodeError> {
169+
let d = self.as_view().get_data();
170+
let writer = encoder.writer();
171+
writer.write(&[0])?;
172+
writer.write(&d.len().to_le_bytes())?;
173+
writer.write(d)?;
174+
Ok(())
175+
}
176+
}
177+
178+
#[test]
179+
fn encode_decode() {
180+
let a = Atom::new_num(1);
181+
let encoded_a = bincode::encode_to_vec(a, bincode::config::standard()).unwrap();
182+
let mut export = vec![];
183+
State::export(&mut export).unwrap();
184+
185+
let mut i = State::import(&mut Cursor::new(&export), None).unwrap();
186+
187+
let (atom, d) = bincode::decode_from_slice_with_context::<_, Atom, _>(
188+
&encoded_a,
189+
bincode::config::standard(),
190+
&mut i,
191+
)
192+
.unwrap();
193+
}
194+
impl_borrow_decode_with_context!(Atom, StateMap);
195+
impl Decode<StateMap> for Atom {
196+
fn decode<D: bincode::de::Decoder<Context = StateMap>>(
197+
decoder: &mut D,
198+
) -> Result<Self, bincode::error::DecodeError> {
199+
let atom = {
200+
let source = decoder.reader();
201+
202+
let mut dest = Atom::Zero.into_raw();
203+
204+
// should also set whether rat poly coefficient needs to be converted
205+
let mut flags_buf = [0; 1];
206+
let mut size_buf = [0; 8];
207+
208+
source.read(&mut flags_buf)?;
209+
source.read(&mut size_buf)?;
210+
211+
let n_size = u64::from_le_bytes(size_buf);
212+
213+
dest.extend(size_buf);
214+
dest.resize(n_size as usize, 0);
215+
source.read(&mut dest)?;
216+
217+
unsafe {
218+
match dest[0] & TYPE_MASK {
219+
NUM_ID => Atom::Num(Num::from_raw(dest)),
220+
VAR_ID => Atom::Var(Var::from_raw(dest)),
221+
FUN_ID => Atom::Fun(Fun::from_raw(dest)),
222+
MUL_ID => Atom::Mul(Mul::from_raw(dest)),
223+
ADD_ID => Atom::Add(Add::from_raw(dest)),
224+
POW_ID => Atom::Pow(Pow::from_raw(dest)),
225+
_ => unreachable!("Unknown type {}", dest[0]),
226+
}
227+
}
228+
};
229+
230+
let state_map = decoder.context();
231+
Ok(atom.as_view().rename(&state_map))
232+
}
233+
}
234+
160235
impl Atom {
161236
/// Read from a binary stream. The format is the byte-length first
162237
/// followed by the data.

src/domains/integer.rs

+65
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ use std::{
55
str::FromStr,
66
};
77

8+
use bincode::{
9+
de::read::Reader,
10+
enc::write::Writer,
11+
error::{DecodeError, EncodeError},
12+
impl_borrow_decode, Decode, Encode,
13+
};
814
use rand::Rng;
915
use rug::{
1016
ops::{Pow, RemRounding},
@@ -63,6 +69,65 @@ pub enum Integer {
6369
Large(MultiPrecisionInteger),
6470
}
6571

72+
impl Encode for Integer {
73+
fn encode<E: bincode::enc::Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
74+
match self {
75+
Integer::Natural(val) => {
76+
// Variant tag
77+
0u8.encode(encoder)?;
78+
val.encode(encoder)
79+
}
80+
Integer::Double(val) => {
81+
1u8.encode(encoder)?;
82+
val.encode(encoder)
83+
}
84+
Integer::Large(val) => {
85+
2u8.encode(encoder)?;
86+
// Convert the MultiPrecisionInteger to bytes.
87+
// For rug::Integer, `to_digits` allows conversion to a Vec<u8>.
88+
// Use Order::MsfBe for most-significant-first (big-endian).
89+
let bytes = val.to_digits::<u8>(rug::integer::Order::MsfBe);
90+
91+
// Encode the length of the byte array
92+
(bytes.len() as u64).encode(encoder)?;
93+
encoder.writer().write(&bytes)
94+
}
95+
}
96+
}
97+
}
98+
99+
impl<C> Decode<C> for Integer {
100+
fn decode<D: bincode::de::Decoder<Context = C>>(decoder: &mut D) -> Result<Self, DecodeError> {
101+
let variant = u8::decode(decoder)?;
102+
match variant {
103+
0 => {
104+
let val = i64::decode(decoder)?;
105+
Ok(Integer::Natural(val))
106+
}
107+
1 => {
108+
let val = i128::decode(decoder)?;
109+
Ok(Integer::Double(val))
110+
}
111+
2 => {
112+
// Decode the length
113+
let length = u64::decode(decoder)? as usize;
114+
let mut bytes = vec![0u8; length];
115+
decoder.reader().read(&mut bytes)?;
116+
117+
// Convert bytes back into a MultiPrecisionInteger
118+
// For rug::Integer, from_digits can reconstruct from big-endian bytes:
119+
let val = MultiPrecisionInteger::from_digits(&bytes, rug::integer::Order::MsfBe);
120+
Ok(Integer::Large(val))
121+
}
122+
_ => Err(bincode::error::DecodeError::OtherString(format!(
123+
"Invalid variant for Integer: {}",
124+
variant
125+
))),
126+
}
127+
}
128+
}
129+
130+
impl_borrow_decode!(Integer);
66131
impl InternalOrdering for Integer {
67132
fn internal_cmp(&self, other: &Self) -> std::cmp::Ordering {
68133
Ord::cmp(self, other)

src/domains/rational.rs

+43
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ use std::{
44
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
55
};
66

7+
use bincode::{
8+
de::{BorrowDecoder, Decoder},
9+
enc::Encoder,
10+
error::{DecodeError, EncodeError},
11+
impl_borrow_decode, BorrowDecode, Decode, Encode,
12+
};
13+
714
use crate::{
815
poly::{gcd::LARGE_U32_PRIMES, polynomial::PolynomialRing, Exponent},
916
printer::{PrintOptions, PrintState},
@@ -117,6 +124,42 @@ pub struct Fraction<R: Ring> {
117124
denominator: R::Element,
118125
}
119126

127+
impl<R: Ring> Encode for Fraction<R>
128+
where
129+
R::Element: Encode,
130+
{
131+
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
132+
self.numerator.encode(encoder)?;
133+
self.denominator.encode(encoder)
134+
}
135+
}
136+
137+
impl<C, R: Ring> Decode<C> for Fraction<R>
138+
where
139+
R::Element: Decode<C>,
140+
{
141+
fn decode<D: Decoder<Context = C>>(decoder: &mut D) -> Result<Self, DecodeError> {
142+
Ok(Fraction {
143+
numerator: R::Element::decode(decoder)?,
144+
denominator: R::Element::decode(decoder)?,
145+
})
146+
}
147+
}
148+
149+
impl<'de, C, R: Ring> BorrowDecode<'de, C> for Fraction<R>
150+
where
151+
R::Element: BorrowDecode<'de, C>,
152+
{
153+
fn borrow_decode<D: BorrowDecoder<'de, Context = C>>(
154+
decoder: &mut D,
155+
) -> Result<Self, DecodeError> {
156+
Ok(Fraction {
157+
numerator: R::Element::borrow_decode(decoder)?,
158+
denominator: R::Element::borrow_decode(decoder)?,
159+
})
160+
}
161+
}
162+
120163
impl<R: Ring> Fraction<R> {
121164
pub fn new(numerator: R::Element, denominator: R::Element) -> Fraction<R> {
122165
Fraction {

0 commit comments

Comments
 (0)