Compartir a través de


Tutorial del lector RSS (Rust para Windows con VS Code)

En el tema anterior se presentó Rust para Windows y crate windows.

Ahora, para probar Rust para Windows, vamos a escribir una aplicación de consola sencilla que descargue los títulos de las entradas de blog de una fuente de Really Simple Syndication (RSS).

  1. Inicie un símbolo del sistema (cmd.exe) y cd en la carpeta donde quiera conservar los proyectos de Rust.

  2. Con Cargo, cree un nuevo proyecto de Rust denominado rss_reader y aplique cd en la carpeta recién creada.

    > cargo new rss_reader
    >     Created binary (application) `rss_reader` package
    > cd rss_reader
    
  3. A continuación, abra el proyecto rss_reader en VS Code.

    code .
    
  4. Ahora vamos a implementar el proyecto rss_reader principal. En primer lugar, abra el archivo Cargo.toml en la raíz del proyecto. Un archivo Cargo.toml es un archivo de texto que describe un proyecto de Rust, incluidas las dependencias que tenga.

    Agregue una dependencia en el crate windows, como se muestra en la lista siguiente. El crate windows es grande. Para mantener los tiempos de compilación rápidos, seleccionaremos solo las características Foundation_Collections y Web_Syndication que necesitamos para este código.

    # Cargo.toml
    ...
    
    [dependencies.windows] 
    version = "0.43.0"
    features = [
        "Foundation_Collections",
        "Web_Syndication",
    ]
    
  5. Por último, abra el archivo de código fuente src/main.rs del proyecto rss_reader. Allí encontrará el código predeterminado "Hola, mundo!" de Cargo. Agregue la siguiente instrucción use al principio de main.rs:

    // src\main.rs
    use windows::{
        core::*,
        Foundation::Uri,
        Web::Syndication::SyndicationClient
    };
    
    fn main() {
        println!("Hello, world!");
    }
    

    La declaración use acorta la ruta de acceso a los tipos que se van a usar. Allí está el tipo Uri mencionado anteriormente.

  6. Para crear un nuevo URI, reemplace la función main predeterminada de Cargo por esta:

    // src\main.rs
    ...
    
    fn main() -> Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
    
        Ok(())
    }
    

    Observe que el tipo de valor devuelto de la función main es un resultado, de windows::core::. Esto facilitará las cosas, ya que es habitual tratar los errores desde las API de sistema operativo (SO). Así pues, windows::core::Resultv nos ayuda con la propagación de errores y a realizar un control de errores conciso.

    Puede ver el operador de signo de interrogación al final de la línea de código. Para ahorrar en escritura, hacemos esto para usar la propagación de errores y la lógica de cortocircuito de Rust. Esto significa que no es necesario un gran trabajo de control manual de errores para este sencillo ejemplo. Para obtener más información sobre esta característica de Rust, consulte The ? operator for easier error handling (El operador ? para facilitar el control de errores).

    Observe también la macro h! del crate windows. Se usa para construir una referencia a HSTRING a partir de un literal de cadena de Rust. La API de WinRT usa HSTRING ampliamente para los valores de cadena.

  7. Para descargar la fuente RSS, vamos a crear un nuevo objeto SyndicationClient.

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
    
        Ok(())
    }
    

    La nueva función es un constructor de Rust. Todos los objetos del crate windows siguen la convención de Rust y asignan un nombre a sus constructores nuevos.

  8. Ahora se puede usar el objeto SyndicationClient para recuperar la fuente.

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
        let feed = client.RetrieveFeedAsync(&uri)?.get()?;
    
        Ok(())
    }
    

    Dado que RetrieveFeedAsync es una API asincrónica, usamos la función de bloqueo get para simplificar el ejemplo. Como alternativa, podríamos usar el operador await dentro de una función async para esperar los resultados de forma cooperativa. Una aplicación más compleja con una interfaz gráfica de usuario usará async con frecuencia.

  9. Ahora podemos recorrer en iteración los elementos resultantes e imprimir solo los títulos. También verá algunas líneas de código adicionales a continuación para establecer un encabezado de agente de usuario, ya que algunas fuentes RSS lo requieren.

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
    
        client.SetRequestHeader(
            h!("User-Agent"),
            h!("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"),
        )?;
    
        let feed = client.RetrieveFeedAsync(&uri)?.get()?;
    
        for item in feed.Items()? {
            println!("{}", item.Title()?.Text()?);
        }
    
        Ok(())
    }
    
  10. Ahora vamos a confirmar que se puede compilar y ejecutar haciendo clic en Ejecutar>Ejecutar sin depuración (o presionando CTRL+F5). Si ve algún mensaje inesperado, asegúrese de que ha completado correctamente el tutorial Hello, world! (Rust con VS Code).

    También hay comandos Debug y Run insertados en el editor de texto. Como alternativa, desde un símbolo del sistema en la carpeta rss_reader, escriba cargo run, que compilará y, a continuación, ejecutará el programa.

    Los comandos Debug y Run insertados en el editor de texto

    En el panel Terminal de VS Code, puede ver que Cargo descarga y compila correctamente el crate windows, almacena en caché los resultados y los usa para que las compilaciones posteriores se completen en menos tiempo. A continuación, compila el ejemplo y lo ejecuta, y muestra una lista de los títulos de las entradas de blog.

    Lista de títulos de las entradas de blog

Así de sencillo es programar Rust para Windows. Sin embargo, aunque no resulte evidente, se ha puesto gran empeño para crear las herramientas para que Rust pueda analizar archivos .winmd basados en ECMA-335 (Common Language Infrastructure o CLI) y, a la vez, respetar de manera fiel la interfaz binaria de aplicaciones (ABI) basada en COM en tiempo de ejecución, teniendo en cuenta tanto la seguridad como la eficacia.

Muestra de un cuadro de mensaje

Se indicó con anterioridad que Rust para Windows le permite llamar a cualquier API de Windows (pasada, presente y futura). Por lo tanto, en esta sección se mostrarán un par de cuadros de mensaje de Windows.

  1. Al igual que hicimos para el proyecto RSS, en el símbolo del sistema cd a la carpeta con los proyectos de Rust.

  2. Cree un proyecto denominado message_box y ábralo en VS Code:

    > cargo new message_box
    >     Created binary (application) `message_box` package
    > cd message_box
    > code .
    
  3. En VS Code, abra Cargo.toml y agregue las dependencias de Windows para este proyecto:

     # message_box\Cargo.toml
     ...
    
     [dependencies.windows]
     version = "0.43.0"
     features = [
         "Win32_Foundation",
         "Win32_UI_WindowsAndMessaging",
     ]
    
  4. Ahora abra el archivo src/main.rs del proyecto y agregue las declaraciones use con los nuevos espacios de nombres (como se muestra a continuación). Y, por último, agregue código para llamar a las funciones MessageBoxA y MessageBoxW. Los documentos de la API de Windows se escriben principalmente teniendo en cuenta C/C++, por lo que resulta útil comparar los documentos de API con los documentos de las proyecciones de Rust en el crate windows: MessageBoxA (Rust) y MessageBoxW (Rust).

    // src\main.rs
    use windows::{
        core::*,
        Win32::UI::WindowsAndMessaging::*
    };
    
    fn main() {
        unsafe {
            MessageBoxA(None, s!("Ansi"), s!("World"), MB_OK);
            MessageBoxW(None, w!("Wide"), w!("World"), MB_OK);
        }
    }
    

    Como puede ver, debemos usar estas API de Win32 en un bloque unsafe (consulte Bloques no seguros). Observe también las macros s! y w! que crean argumentos LPCSTR y LPCWSTR a partir de literales de cadena UTF-8 de Rust; al igual que creamos un HSTRING con la macro h! para rss_reader. Rust es Unicode de forma nativa con cadenas UTF-8, por lo que se prefiere usar las API de Windows Unicode (W-sufijo) anchos sobre las API de ANSI (sufijo A). Esto puede ser importante si usa texto no en inglés en el código.

Esta vez, cuando realice una compilación y la ejecute, Rust mostrará un cuadro de mensaje de Windows después de enumerar los títulos de las publicaciones del blog.