Skip to content

Commit 8c22038

Browse files
lcnbrlcnbr
lcnbr
authored andcommitted
use a bincode PR to implement derived Encode and Decode with StateMap as context
1 parent 4b13bae commit 8c22038

11 files changed

+357
-11
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.23"
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

+46
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ mod coefficient;
4343
mod core;
4444
pub mod representation;
4545

46+
use bincode::{de::read::Reader, enc::write::Writer, Decode, Encode};
4647
use colored::Colorize;
48+
4749
use representation::InlineVar;
4850
use smartstring::{LazyCompact, SmartString};
4951

@@ -287,6 +289,7 @@ pub enum FunctionAttribute {
287289
Linear,
288290
}
289291

292+
use std::result;
290293
/// A symbol, for example the name of a variable or the name of a function,
291294
/// together with its properties.
292295
///
@@ -313,6 +316,49 @@ pub struct Symbol {
313316
is_linear: bool,
314317
}
315318

319+
impl<__Context> ::bincode::Decode<__Context> for Symbol {
320+
fn decode<__D: ::bincode::de::Decoder<Context = __Context>>(
321+
decoder: &mut __D,
322+
) -> Result<Self, ::bincode::error::DecodeError> {
323+
Ok(Self {
324+
id: ::bincode::Decode::decode(decoder)?,
325+
wildcard_level: ::bincode::Decode::decode(decoder)?,
326+
is_symmetric: ::bincode::Decode::decode(decoder)?,
327+
is_antisymmetric: ::bincode::Decode::decode(decoder)?,
328+
is_cyclesymmetric: ::bincode::Decode::decode(decoder)?,
329+
is_linear: ::bincode::Decode::decode(decoder)?,
330+
})
331+
}
332+
}
333+
impl<'__de, __Context> ::bincode::BorrowDecode<'__de, __Context> for Symbol {
334+
fn borrow_decode<__D: ::bincode::de::BorrowDecoder<'__de, Context = __Context>>(
335+
decoder: &mut __D,
336+
) -> Result<Self, ::bincode::error::DecodeError> {
337+
Ok(Self {
338+
id: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
339+
wildcard_level: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
340+
is_symmetric: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
341+
is_antisymmetric: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
342+
is_cyclesymmetric: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
343+
is_linear: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
344+
})
345+
}
346+
}
347+
348+
impl ::bincode::Encode for Symbol {
349+
fn encode<__E: ::bincode::enc::Encoder>(
350+
&self,
351+
encoder: &mut __E,
352+
) -> Result<(), ::bincode::error::EncodeError> {
353+
::bincode::Encode::encode(&self.id, encoder)?;
354+
::bincode::Encode::encode(&self.wildcard_level, encoder)?;
355+
::bincode::Encode::encode(&self.is_symmetric, encoder)?;
356+
::bincode::Encode::encode(&self.is_antisymmetric, encoder)?;
357+
::bincode::Encode::encode(&self.is_cyclesymmetric, encoder)?;
358+
::bincode::Encode::encode(&self.is_linear, encoder)?;
359+
Ok(())
360+
}
361+
}
316362
impl std::fmt::Debug for Symbol {
317363
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318364
f.write_fmt(format_args!("{}", self.id))?;

src/atom/representation.rs

+76-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
//! Low-level representation of expressions.
2-
2+
use bincode::{
3+
de::read::Reader, enc::write::Writer, impl_borrow_decode_with_context, BorrowDecode, Decode,
4+
Encode,
5+
};
36
use byteorder::{LittleEndian, WriteBytesExt};
47
use bytes::{Buf, BufMut};
58
use smartstring::alias::String;
69
use std::{
710
borrow::Borrow,
811
cmp::Ordering,
912
hash::Hash,
10-
io::{Read, Write},
13+
io::{Cursor, Read, Write},
1114
};
1215

1316
use crate::{
@@ -161,6 +164,77 @@ impl InlineNum {
161164
}
162165
}
163166

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

src/domains/integer.rs

+65
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ use std::{
77
str::FromStr,
88
};
99

10+
use bincode::{
11+
de::read::Reader,
12+
enc::write::Writer,
13+
error::{DecodeError, EncodeError},
14+
impl_borrow_decode, Decode, Encode,
15+
};
1016
use rand::Rng;
1117
use rug::{
1218
ops::{Pow, RemRounding},
@@ -67,6 +73,65 @@ pub enum Integer {
6773
Large(MultiPrecisionInteger),
6874
}
6975

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

src/domains/rational.rs

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

9+
use bincode::{
10+
de::{BorrowDecoder, Decoder},
11+
enc::Encoder,
12+
error::{DecodeError, EncodeError},
13+
impl_borrow_decode, BorrowDecode, Decode, Encode,
14+
};
15+
916
use crate::{
1017
poly::{gcd::LARGE_U32_PRIMES, polynomial::PolynomialRing, Exponent},
1118
printer::{PrintOptions, PrintState},
@@ -120,6 +127,42 @@ pub struct Fraction<R: Ring> {
120127
denominator: R::Element,
121128
}
122129

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

0 commit comments

Comments
 (0)