binius_core/transparent/
serialization.rs

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