binius_core/transparent/
serialization.rs

1// Copyright 2025 Irreducible Inc.
2
3//! The purpose of this module is to enable serialization/deserialization of generic MultivariatePoly implementations
4//!
5//! The simplest way to do this would be to create an enum with all the possible structs that implement MultivariatePoly
6//!
7//! This has a few problems, though:
8//! - Third party code is not able to define custom transparent polynomials
9//! - The enum would inherit, or be forced to enumerate possible type parameters of every struct variant
10
11use std::{collections::HashMap, sync::LazyLock};
12
13use binius_field::{BinaryField128b, TowerField};
14use binius_utils::{DeserializeBytes, SerializationError, SerializationMode, SerializeBytes};
15
16use crate::polynomial::MultivariatePoly;
17
18impl<F: TowerField> SerializeBytes for Box<dyn MultivariatePoly<F>> {
19	fn serialize(
20		&self,
21		mut write_buf: impl bytes::BufMut,
22		mode: SerializationMode,
23	) -> Result<(), SerializationError> {
24		self.erased_serialize(&mut write_buf, mode)
25	}
26}
27
28impl DeserializeBytes for Box<dyn MultivariatePoly<BinaryField128b>> {
29	fn deserialize(
30		mut read_buf: impl bytes::Buf,
31		mode: SerializationMode,
32	) -> Result<Self, SerializationError>
33	where
34		Self: Sized,
35	{
36		let name = String::deserialize(&mut read_buf, mode)?;
37		match REGISTRY.get(name.as_str()) {
38			Some(Some(erased_deserialize)) => erased_deserialize(&mut read_buf, mode),
39			Some(None) => Err(SerializationError::DeserializerNameConflict { name }),
40			None => Err(SerializationError::DeserializerNotImplented),
41		}
42	}
43}
44
45// Using the inventory crate we can collect all deserializers before the main function runs
46// This allows third party code to submit their own deserializers as well
47inventory::collect!(DeserializerEntry<BinaryField128b>);
48
49static REGISTRY: LazyLock<HashMap<&'static str, Option<ErasedDeserializeBytes<BinaryField128b>>>> =
50	LazyLock::new(|| {
51		let mut registry = HashMap::new();
52		inventory::iter::<DeserializerEntry<BinaryField128b>>
53			.into_iter()
54			.for_each(|&DeserializerEntry { name, deserializer }| match registry.entry(name) {
55				std::collections::hash_map::Entry::Vacant(entry) => {
56					entry.insert(Some(deserializer));
57				}
58				std::collections::hash_map::Entry::Occupied(mut entry) => {
59					entry.insert(None);
60				}
61			});
62		registry
63	});
64
65impl<F: TowerField> dyn MultivariatePoly<F> {
66	pub const fn register_deserializer(
67		name: &'static str,
68		deserializer: ErasedDeserializeBytes<F>,
69	) -> DeserializerEntry<F> {
70		DeserializerEntry { name, deserializer }
71	}
72}
73
74pub struct DeserializerEntry<F: TowerField> {
75	name: &'static str,
76	deserializer: ErasedDeserializeBytes<F>,
77}
78
79type ErasedDeserializeBytes<F> = fn(
80	&mut dyn bytes::Buf,
81	mode: SerializationMode,
82) -> Result<Box<dyn MultivariatePoly<F>>, SerializationError>;