BookinglyTech News
Software

Deser, el experimento de Armin Ronacher para repensar Serde en Rust

El autor de Flask retoma una biblioteca de serialización que empezó en 2022 y llevaba años parada: misma ergonomía que Serde, arquitectura completamente distinta.

3 min de lecturaLobsters0 vistas

Armin Ronacher ha retomado Deser, una biblioteca de serialización para Rust que empezó a escribir en 2022 y que llevaba años parada. El nombre es Serde con las dos mitades cambiadas, y la ambición es la misma: dar la experiencia de uso de Serde sobre una arquitectura completamente distinta, inspirada en miniserde. Ronacher no lo vende como un reemplazo listo para producción, sino como algo que ya merece un vistazo y que puede empujar a otros a explorar el terreno.

Por qué Serde se queda corto

El punto de partida son tres casos que Ronacher se encontró una y otra vez mientras trabajaba en Sentry Relay, procesando cantidades enormes de JSON no confiable. Ninguno es un bug fácil de parchear: salen del diseño de Serde, y ese diseño está protegido por sus garantías de estabilidad, así que tocarlos rompería todos los formatos y todas las implementaciones escritas a mano.

El primero: un número que es un mapa. Con la feature arbitrary_precision de serde_json activada, la biblioteca representa los números de precisión arbitraria con una señalización en banda, un mapa con una clave mágica, porque el modelo de datos de Serde no tiene sitio para ellos. Un enum con tag interno debe ir guardando los campos hasta ver la etiqueta, y ese búfer no conoce la clave. Basta con que cualquier crate del árbol de dependencias active la feature, porque Cargo unifica features.

El segundo: flatten rompe las claves enteras. Un HashMap<u32, u32> parsea bien sus claves "42" porque serde_json las convierte a entero cuando el tipo lo pide. En cuanto flatten mete el valor en un búfer, "42" vuelve a ser un string. El error, además, apunta al final del documento y no a la clave.

El tercero: los adaptadores no componen. Una función de deserialización como from_hex no se puede aplicar al interior de un Option, un Vec o un map, porque una función no puede pasarse como parámetro de tipo. Toca escribir otra función por cada envoltorio, y al hacerlo el campo deja de ser opcional salvo que se añada #[serde(default)].

Cómo funciona Deser

Deser invierte el flujo. En Serde es el tipo el que dirige la deserialización y cada valor anidado gasta pila. En Deser es el formato el que anuncia el tipo del siguiente valor y empuja eventos a un sink; cuando el sink llega al inicio de un valor anidado no entra en él, sino que devuelve un sink nuevo a un driver, con todo el estado en el heap, en un arena. A la salida, los emisores devuelven sus valores anidados en vez de recursar.

Eso tiene precio: Deser no puede soportar formatos que no se describen a sí mismos, como protobuf, y quedan fuera del diseño a propósito. A cambio, una deserialización puede pausarse mientras se espera más entrada, y el anidamiento profundo deja de ser una vía para tumbar el proceso.

El código y las notas de diseño están en el repositorio.

Lo interesante no es que Deser vaya a sustituir a Serde, porque su autor lo plantea como un experimento abierto. Es que demuestra que se puede cambiar la arquitectura por debajo y conservar la ergonomía por encima, a base de renunciar a los formatos no autodescriptivos. Para quien mantiene un parser en Rust, los tres ejemplos ya justifican la lectura, porque aplican a cualquier biblioteca de serialización y no solo a esta.