Tutorial do leitor do RSS (Rust para Windows com VS Code)

O tópico anterior apresentou o Rust para Windows e o crate windows.

Agora vamos experimentar o Rust para Windows escrevendo um aplicativo de console simples que baixa os títulos de postagens de blog de um feed RSS (Really Simple Syndication).

  1. Inicialize um prompt de comando (cmd.exe) e cd para uma pasta onde você deseja manter seus projetos do Rust.

  2. Usando o Cargo, crie um novo projeto Rust chamado rss_readere cd para a pasta recém-criada:

    > cargo new rss_reader
    >     Created binary (application) `rss_reader` package
    > cd rss_reader
    
  3. Em seguida, abra o projeto rss_reader no VS Code.

    code .
    
  4. Vamos implementar o projeto principal rss_reader. Primeiro, abra o Cargo.toml arquivo na raiz do projeto. Um Cargo.toml arquivo é um arquivo de texto que descreve um projeto em Rust, incluindo as dependências que ele tem.

    Adicione uma dependência ao crate windows, conforme mostrado na listagem abaixo. O crate windows é grande. Para manter os tempos de build rápidos, selecionaremos apenas as características Foundation_Collections e Web_Syndication necessárias para este código.

    # Cargo.toml
    ...
    
    [dependencies.windows] 
    version = "0.62.0"
    features = [
        "Foundation_Collections",
        "Web_Syndication",
    ]
    

    Note

    O crate windows é lançado frequentemente. Verifique crates.io/crates/windows para obter a versão mais recente e atualize adequadamente.

  5. Em seguida, abra o arquivo de código-fonte do src/main.rs projeto. Lá, você encontrará o código padrão "Olá, mundo!" do Cargo. Adicione a seguinte instrução use ao início de main.rs:

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

    A declaração use reduz o caminho para os tipos que usaremos. Há o tipo Uri que mencionamos anteriormente.

  6. Para criar um novo Uri, substitua a função main padrão do Cargo por esta:

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

    Observe que o tipo de retorno da função main é um Resultado, com base em windows::core::. Isso facilitará as coisas, pois é comum lidar com erros de APIs do sistema operacional (SO). windows::core::Result nos ajuda com a propagação de erros e o tratamento conciso de erros.

    Você pode ver o operador de ponto de interrogação no final da linha de código. Para economizar na digitação, fazemos isso para utilizar a lógica de propagação de erro e curto-circuito do Rust. Isso significa que não precisamos fazer um monte de tratamento manual de erros para este exemplo simples. Para obter mais informações sobre esse recurso do Rust, consulte O operador ? para facilitar o tratamento de erros.

    Observe também a macro h! do crate windows. Usamos isso para construir uma referência HSTRING com base em um literal de cadeia de caracteres Rust. A API do WinRT usa o HSTRING extensivamente para valores de cadeia de caracteres.

  7. Para baixar o feed RSS, criaremos um novo SyndicationClient.

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

    A função new é um construtor Rust. Todos os objetos no crate windows seguem a convenção Rust e nomeiam os construtores deles como new.

  8. Agora podemos usar o SyndicationClient para recuperar o feed.

    // 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(())
    }
    

    Como RetrieveFeedAsync é uma API assíncrona, usamos a função de obtenção de bloqueio para manter o exemplo simples. Como alternativa, poderíamos usar o await operador dentro de uma async função para aguardar cooperativamente os resultados. Um aplicativo mais complexo com uma interface gráfica do usuário frequentemente usará async.

  9. Podemos iterar nos itens resultantes e imprimir apenas os títulos. Você também verá algumas linhas extras de código abaixo para definir um cabeçalho de agente de usuário, já que alguns feeds RSS exigem isso.

    // 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. Agora, vamos confirmar se podemos compilar e executar clicando em Executar>Executar sem depuração (ou pressionando Ctrl+F5). Se você vir mensagens inesperadas, verifique se concluiu com êxito o tutorial Olá, mundo! (Rust com VS Code).

    Também há comandos Debug e Run inseridos dentro do editor de texto. Como alternativa, a partir de um prompt de comando na pasta rss_reader, digite cargo run, que irá compilar e executar o programa.

    Os comandos Depurar e Executar inseridos no editor de texto

    No painel Terminal do VS Code, você pode ver que o Cargo baixou e compilou com sucesso o crate windows, armazenando os resultados em cache e usando-os para que as compilações subsequentes sejam concluídas em menos tempo. Em seguida, ele cria o exemplo e o executa, exibindo uma lista de títulos de postagem no blog.

    Lista de títulos de postagem no blog

Isso é tão simples quanto é programar o Rust para Windows. Mas, no fundo, grande parte da simplicidade consiste em criar as ferramentas para que o Rust possa analisar arquivos .winmd com base em ECMA-335 (Common Language Infrastructure ou CLI) e também usar de forma segura a ABI (interface binária de aplicativos) baseada em COM em tempo de execução, sempre colocando a segurança e a eficiência em primeiro lugar.

Mostrando uma caixa de mensagem

Dissemos que o Rust para Windows permite que você chame qualquer API do Windows (passado, presente e futuro). Portanto, nesta seção, mostraremos algumas caixas de mensagem do Windows.

  1. Assim como fizemos no projeto RSS, no prompt de comando cd para a pasta com seus projetos do Rust.

  2. Crie um novo projeto chamado message_box e abra-o no VS Code:

    > cargo new message_box
    >     Created binary (application) `message_box` package
    > cd message_box
    > code .
    
  3. No VS Code, abra o Cargo.toml, e então adicione as dependências do Windows para este projeto:

     # message_box\Cargo.toml
     ...
    
     [dependencies.windows]
     version = "0.62.0"
     features = [
         "Win32_Foundation",
         "Win32_UI_WindowsAndMessaging",
     ]
    
  4. Agora, abra o arquivo do src/main.rs projeto e adicione as use declarações com os novos namespaces (conforme mostrado abaixo). E, por fim, adicione código para chamar as funções MessageBoxA e MessageBoxW . Os documentos da API do Windows são principalmente escritos com C/C++ em mente, então é útil comparar os documentos da API com os documentos para as projeções do Rust no crate windows: MessageBoxA (Rust) e 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 você pode ver, devemos usar essas APIs Win32 em um unsafe bloco (consulte blocos não seguros). Observe também as macros s! e w!, que criam argumentos LPCSTR e LPCWSTR de literais de cadeia de caracteres UTF-8 Rust; assim como criamos um HSTRING com a macro h! para rss_reader. O Rust é, nativamente, um Unicode com cadeias de caracteres UTF-8, portanto, o uso das APIs amplas do Windows Unicode (sufixo W) é preferencial ao das APIs ANSI (sufixo A). Isso pode ser importante se você usar texto não inglês em seu código.

Desta vez, quando você cria e executa, o Rust exibe duas caixas de mensagem do Windows.