No es tan difícil. Se puede hacer. Además, no estoy aquí para iniciar una nueva discusión sobre lenguajes. No soy un troll, o al menos no tanto. Así que por favor, sean amables. No inicien una discusión sobre lenguajes.
Tampoco estoy criticando a LLHTTP o Feather en absoluto, porque Feather es una persona muy buena, y LLHTTP fue un analizador increíble y eficiente que me encantó. Su arquitectura es la inspiración y la base de Milo, obviamente. Aún tengo una máquina de estados, pero mucho más simple, tengo muchos menos estados. Pasamos de 80 a 32, y elegí usar una forma declarativa de escribir estados, sin restricciones de código en Rust.
Ahora, no es magia negra. Nada es magia negra en TI, ¿verdad? Simplemente aprovecho las macros. El sistema de macros de Rust es uno de los más poderosos, si no el más poderoso, que he visto. Básicamente, la idea es que antes de completar tu código, si usas una macro (no estoy hablando de macros procedurales), básicamente puedes ejecutar otra parte de código Rust que se genera y se compila eventualmente. Entonces, básicamente, la macro en Rust producirá código Rust, pero no tienes ninguna limitación de código, puedes hacer lo que quieras. Por ejemplo, cargo la lista de métodos, estados, etc., desde archivos YAML que no están presentes o incrustados en tiempo de ejecución, porque se pasan en tiempo de compilación, genero código Rust y creo un ejecutable Rust.
También hay una herramienta que está hecha específicamente para depurar la macro procedural en Rust, porque en Rust, generalmente se usan las bibliotecas scene y quote, y con cargo span, puedes ver qué hacen estas bibliotecas con tu código, por lo que puedes tener un paso adicional antes de la compilación. Los ejemplos suelen ser más elocuentes que mil palabras. Echemos un vistazo. Incluso si no eres programador de Rust, puedes ver fácilmente la similitud entre el lado izquierdo y el lado derecho. En el lado izquierdo, tienes un estado real en Milo, que es el estado después de recibir un fragmento y volver a la longitud del siguiente fragmento, eventualmente, si recibes un slash r slash n. De lo contrario, si recibes otros dos caracteres que no esperas, fallas en el análisis. O si no tienes al menos dos caracteres para hacer la comparación, generalmente solo tienes uno, suspendes la ejecución, detienes el análisis por ahora y regresas al llamador. En el lado derecho, después de transpilar las macros, que para que conste son las que terminan en signo de exclamación, tienes el código compilado. Básicamente, el estado se convierte en una función con una firma específica que no tienes que recordar porque está implícita en la macro. CR LF se convierte en slash r slash n, pero con una sintaxis expandida que Rust espera. Lo mismo ocurre con MOV2 que se convierte en analizador MOV2, un estado y un tamaño. Finalmente, también puedes devolver una constante. Pero no tienes que recordar todos estos detalles porque las macros lo harán por ti. Ahora, ¿qué hay de la memoria? Sabemos que Milo es de alto rendimiento, ¿verdad? Pero, ¿qué hay de la huella de memoria? Milo tiene una huella de memoria muy pequeña.
Comments