user-agent-parser 0.3.6

A parser to get the product, OS, device, cpu, and engine information from a user agent, inspired by https://github.com/faisalman/ua-parser-js and https://github.com/ua-parser/uap-core
Documentation
use std::borrow::Cow;

use rocket::{
    outcome::Outcome,
    request::{FromRequest, Outcome as OutcomeResult, Request},
};

use crate::{models::*, UserAgentParser};

fn from_request_user_agent<'r>(request: &'r Request<'_>) -> UserAgent<'r> {
    let user_agent: Option<Cow<'r, str>> =
        request.headers().get("user-agent").next().map(Cow::from);

    UserAgent {
        user_agent,
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for UserAgent<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        Outcome::Success(from_request_user_agent(request))
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for &UserAgent<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        let cache = request.local_cache(|| from_request_user_agent(request).into_owned());

        Outcome::Success(cache)
    }
}

fn from_request_product<'r>(request: &'r Request<'_>) -> Product<'r> {
    let user_agent_parser = request.rocket().state::<UserAgentParser>().unwrap();

    let user_agent: Option<&str> = request.headers().get("user-agent").next();

    match user_agent {
        Some(user_agent) => user_agent_parser.parse_product(user_agent),
        None => Product::default(),
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for Product<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        Outcome::Success(from_request_product(request))
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for &Product<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        let cache =
            request.local_cache_async(async { from_request_product(request).into_owned() }).await;

        Outcome::Success(cache)
    }
}

fn from_request_os<'r>(request: &'r Request<'_>) -> OS<'r> {
    let user_agent_parser = request.rocket().state::<UserAgentParser>().unwrap();

    let user_agent: Option<&str> = request.headers().get("user-agent").next();

    match user_agent {
        Some(user_agent) => user_agent_parser.parse_os(user_agent),
        None => OS::default(),
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for OS<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        Outcome::Success(from_request_os(request))
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for &OS<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        let cache =
            request.local_cache_async(async { from_request_os(request).into_owned() }).await;

        Outcome::Success(cache)
    }
}

fn from_request_device<'r>(request: &'r Request<'_>) -> Device<'r> {
    let user_agent_parser = request.rocket().state::<UserAgentParser>().unwrap();

    let user_agent: Option<&str> = request.headers().get("user-agent").next();

    match user_agent {
        Some(user_agent) => user_agent_parser.parse_device(user_agent),
        None => Device::default(),
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for Device<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        Outcome::Success(from_request_device(request))
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for &Device<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        let cache =
            request.local_cache_async(async { from_request_device(request).into_owned() }).await;

        Outcome::Success(cache)
    }
}

fn from_request_cpu<'r>(request: &'r Request<'_>) -> CPU<'r> {
    let user_agent_parser = request.rocket().state::<UserAgentParser>().unwrap();

    let user_agent: Option<&str> = request.headers().get("user-agent").next();

    match user_agent {
        Some(user_agent) => user_agent_parser.parse_cpu(user_agent),
        None => CPU::default(),
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for CPU<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        Outcome::Success(from_request_cpu(request))
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for &CPU<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        let cache =
            request.local_cache_async(async { from_request_cpu(request).into_owned() }).await;

        Outcome::Success(cache)
    }
}

fn from_request_engine<'r>(request: &'r Request<'_>) -> Engine<'r> {
    let user_agent_parser = request.rocket().state::<UserAgentParser>().unwrap();

    let user_agent: Option<&str> = request.headers().get("user-agent").next();

    match user_agent {
        Some(user_agent) => user_agent_parser.parse_engine(user_agent),
        None => Engine::default(),
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for Engine<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        Outcome::Success(from_request_engine(request))
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for &Engine<'r> {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> OutcomeResult<Self, Self::Error> {
        let cache =
            request.local_cache_async(async { from_request_engine(request).into_owned() }).await;

        Outcome::Success(cache)
    }
}