How to fix "`?` operator has incompatible types" error in rust

I have an app in Rust where I want to get a token from a DB server and would store it in a global variable for reusing. I cannot get it running as I have a compiler error, please help me sort it out. I am stuck with it. The code looks like this:

use lazy_static::lazy_static;
use reqwest::{
    self,
    header::{ACCEPT, CONTENT_TYPE},
    Client,
};
use serde::{Deserialize, Serialize};
use std::{
    env,
};

#[derive(Serialize, Deserialize, Debug)]
struct GeneratedToken {
    app_name: String,
    access_token: String,
    dtable_uuid: String,
    dtable_server: String,
    dtable_socket: String,
    dtable_db: String,
    workspace_id: i32,
    dtable_name: String,
}

impl Default for GeneratedToken {
    fn default() -> GeneratedToken {
        GeneratedToken {
            app_name: "".to_string(),
            access_token: "".to_string(),
            dtable_uuid: "".to_string(),
            dtable_server: "".to_string(),
            dtable_socket: "".to_string(),
            dtable_db: "".to_string(),
            workspace_id: 0,
            dtable_name: "".to_string(),
        }
    }
}

lazy_static! {
    static ref SEATABLE_BASE_URL: &'static str = "https://cloud.seatable.io/api/v2.1/";
    static ref API_TOKEN: &'static str = "token...";
    static ref CLIENT: Client = reqwest::Client::new();
	static ref GENERATED_TOKEN: GeneratedToken = GeneratedToken::default();
}

static mut HAS_TOKEN: bool = false;

async fn get_token() -> Result<(), Box<dyn std::error::Error>> {
    unsafe {
        GENERATED_TOKEN = CLIENT
            .get(format!("{}dtable/app-access-token/", *SEATABLE_BASE_URL))
            .bearer_auth(format!("Bearer {}", *API_TOKEN))
            .header(CONTENT_TYPE, "application/json")
            .header(ACCEPT, "application/json")
            .send()
            .await?
            .json::<GeneratedToken>()
            .await?;
        HAS_TOKEN = true;
        print!("Received token: {}", GENERATED_TOKEN.access_token);
    }
    Ok(())
}

fn main() {
    unsafe {
        if !HAS_TOKEN {
            get_token();
        }
    }
}

On the GENERATED_TOKEN = CLIENT line and the block it follows the compiler throws this error:

'?' operator cannot convert from 'GeneratedToken' to 'GENERATED_TOKEN'

Also posted on Stack Overflow.

Please don't use static mut and unsafe for this. There's no good reason to ever use static mut in fact, and retrieving a token from an HTTP API isn't a good reason for unsafe, either.

In general, you should avoid global state, especially mutable global state. If your application needs a token, then retrieve it in main() and pass it as an argument to functions that need it.

Even if you don't do that, you should use safe abstractions such as once_cell::sync::Lazy instead of hand-rolling your own unsafe.

Chances are, if you don't know how to solve a simple type error, then you aren't able to use unsafe correctly. In fact, your use of the static mut and unsafe is unsound in this specific case – you are not protecting the HAS_TOKEN global with any sort of synchronization, so there is a trivial race condition here, which is Undefined Behavior.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.