1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
use std::any::Any;
use std::rc::Rc;
#[cfg(feature = "query")]
use serde::de::DeserializeOwned;
#[cfg(feature = "query")]
use crate::error::HistoryResult;
/// A history location.
///
/// This struct provides location information at the time
/// [`History::location`][crate::History::location] is called.
#[derive(Clone, Debug)]
pub struct Location {
pub(crate) path: Rc<String>,
pub(crate) query_str: Rc<String>,
pub(crate) hash: Rc<String>,
pub(crate) state: Option<Rc<dyn Any>>,
pub(crate) id: Option<u32>,
}
impl Location {
/// Returns a unique id of current location.
///
/// Returns [`None`] if current location is not created by `gloo::history`.
///
/// # Warning
///
/// Depending on the situation, the id may or may not be sequential / incremental.
pub fn id(&self) -> Option<u32> {
self.id
}
/// Returns the `pathname` of current location.
pub fn path(&self) -> &str {
&self.path
}
/// Returns the queries of current URL in [`&str`].
pub fn query_str(&self) -> &str {
&self.query_str
}
/// Returns the queries of current URL parsed as `T`.
#[cfg(feature = "query")]
pub fn query<T>(&self) -> HistoryResult<T>
where
T: DeserializeOwned,
{
let query = self.query_str();
serde_urlencoded::from_str(query.strip_prefix('?').unwrap_or("")).map_err(|e| e.into())
}
/// Returns the hash fragment of current URL.
pub fn hash(&self) -> &str {
&self.hash
}
/// Returns an Rc'ed state of current location.
///
/// Returns [`None`] if state is not created by `gloo::history`, or state fails to downcast.
pub fn state<T>(&self) -> Option<Rc<T>>
where
T: 'static,
{
self.state.clone().and_then(|m| m.downcast().ok())
}
}
impl PartialEq for Location {
fn eq(&self, rhs: &Self) -> bool {
if let Some(lhs) = self.id() {
if let Some(rhs) = rhs.id() {
return lhs == rhs;
}
}
false
}
}