Execute function pointer?

So I have a vector of tuples. The tuple has three items: A string representing a HTTP-method, a path, and a function pointer.

    type route = (&'static str, &'static str, fn(&Routes) -> BoxFuture<Result<HttpResponse, String>>);

    let routes: std::vec::Vec<route> = vec![
        ("GET", "/", |r| Routes::index(r).boxed())
    ];

In my code I search the vector to see if there is a matching http-method and path.

        if let Some(r) = routes.iter().find(|&&(m, p, _)| m == method && p == path) {
            let (_, _, ro) = *r;
            // ???
        } else {
            return Ok(Routes::not_found().await);
        }

The problem is that I don't know how to execute the function pointer. Note that the functions are async.

ro(routes).await

1 Like

I get the following errors:

error[E0308]: mismatched types
   --> src/main.rs:117:23
    |
117 |             return ro(routes).await;
    |                    -- ^^^^^^ expected `&Routes`, found `&Vec<...>`
    |                    |
    |                    arguments to this function are incorrect
    |
    = note: expected reference `&Routes`
               found reference `&Vec<(&str, &str, fn(&...) -> ...)>`
            the full type name has been written to '/Users/niel/Sites/keyrock/rust-api/target/debug/deps/rust_api-08d99d26dc547348.long-type-3398103651944609301.txt'
error: future cannot be sent between threads safely
   --> src/main.rs:36:22
    |
36  |   ...   tokio::spawn(async move {
    |  ____________________^
37  | | ...       if let Err(e) = process(&mut stream, &cloned_r...
38  | | ...           eprintln!("Error: {}", e);
39  | | ...       }
40  | | ...   });
    | |_______^ future created by async block is not `Send`
    |
note: opaque type is declared here
   --> src/main.rs:114:79
    |
114 | ...c<route>) -> Result<HttpResponse, String> {
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
   --> src/main.rs:23:10
    |
23  | async fn main() -> Result<(), Box<dyn Error>> {
    |          ^^^^
note: future is not `Send` as it awaits another future which is not `Send`
   --> src/main.rs:59:5
    |
59  |     Routes::goto(&http.method, &http.path, routes).await;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl futures_util::Future<Output = Result<HttpResponse, std::string::String>>`, which is not `Send`
note: required by a bound in `tokio::spawn`
   --> /Users/niel/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.35.1/src/task/spawn.rs:166:21
    |
164 |     pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
    |            ----- required by a bound in this function
165 |     where
166 |         F: Future + Send + 'static,
    |                     ^^^^ required by this bound in `spawn`

More code:

type route = (&'static str, &'static str, fn(&Routes) -> BoxFuture<Result<HttpResponse, String>>);

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    
    let server = TcpListener::bind("127.0.0.1:8080").await.expect("Failed to bind to 127.0.0.1:8080");

    // List with all the routes
    let routes: std::vec::Vec<route> = vec![
        ("GET", "/", |r| Routes::index(r).boxed())
    ];

    loop {
        let cloned_routes = routes.clone();
        let (mut stream, _) = server.accept().await.unwrap();
        tokio::spawn(async move {
            if let Err(e) = process(&mut stream, cloned_routes).await {
                eprintln!("Error: {}", e);
            }
        });
    }
}

// Function to process stream and defer to matching route.
// E.G:
// GET / HTTP/1.1 will go to Route::index
async fn process(stream: &mut TcpStream, routes: std::vec::Vec<route>) -> Result<(), Box<dyn Error>> {
    let mut buffer = [0; 1024];

    stream.read(&mut buffer).await;
    
    let stream_string = String::from_utf8_lossy(&buffer[..]);

    let http = Http::from_str(&stream_string);
    

    // HERE I WILL HANDLE THE ROUTES
    // ...

    Ok(())
}

struct Http {
    method: String,
    path: String,
    host: String,
    cookies: std::collections::HashMap<String, String>,
}

impl Http {
    fn from_str(str: &str) -> Self {
        println!("{}", str);
        let lines : std::vec::Vec<&str> = str.lines().collect();
        let request_line : std::vec::Vec<&str> = lines[0].split_whitespace().collect();
        
        let method = request_line[0];
        let path = request_line[1];
        let host = lines[1].split_whitespace().collect::<std::vec::Vec<&str>>()[1];
        
        Http {
            method: method.into(),
            path: path.into(),
            host: host.into(),
            cookies: std::collections::HashMap::new(),
        }
    }
}

struct HttpResponse {
    status: u16,
    content_type: String,
    body: String,
}

impl std::fmt::Display for HttpResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f, 
            "HTTP/1.1 {status}\nContent-Type: {content_type}\n\n{body}",
            status = self.status,
            content_type = self.content_type,
            body = self.body
        )
    }
}


struct Routes;
impl Routes {
    async fn index(&self) -> Result<HttpResponse, String> {
        Ok(HttpResponse {
            status: 200,
            content_type: "text/plain".into(),
            body: "Welcome".into(),
        })
    }
}

Oh I got it fixed.
index takes &self as parameter. Had to do it like this:

            return ro(&Routes).await;

Routes is my struct.

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.