create server_cached function

This commit is contained in:
Evan Almloff committed 2023-07-14 17:23:12 -07:00
1 parent d885846589
commit de72d85391
8 files changed
+182 -14

No files matched your search

@@ -0,0 +1,56 @@
use serde::de::DeserializeOwned;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use super::HTMLDataCursor;
#[allow(unused)]
pub(crate) fn serde_from_bytes<T: DeserializeOwned>(string: &[u8]) -> Option<T> {
let decompressed = STANDARD.decode(string).ok()?;
postcard::from_bytes(&decompressed).ok()
}
static SERVER_DATA: once_cell::sync::Lazy<Option<HTMLDataCursor>> =
once_cell::sync::Lazy::new(|| {
#[cfg(target_arch = "wasm32")]
{
let attribute = web_sys::window()?
.document()?
.get_element_by_id("dioxus-storage-data")?
.get_attribute("data-serialized")?;
let data: super::HTMLData = serde_from_bytes(attribute.as_bytes())?;
Some(data.cursor())
}
#[cfg(not(target_arch = "wasm32"))]
{
None
}
});
pub(crate) fn take_server_data<T: DeserializeOwned>() -> Option<T> {
SERVER_DATA.as_ref()?.take()
}
#[cfg(not(feature = "ssr"))]
/// Get the props from the document. This is only available in the browser.
///
/// When dioxus-fullstack renders the page, it will serialize the root props and put them in the document. This function gets them from the document.
pub fn get_root_props_from_document<T: DeserializeOwned>() -> Option<T> {
#[cfg(not(target_arch = "wasm32"))]
{
None
}
#[cfg(target_arch = "wasm32")]
{
let attribute = web_sys::window()?
.document()?
.get_element_by_id("dioxus-storage-props")?
.get_attribute("data-serialized")?;
serde_from_bytes(attribute.as_bytes())
}
}
@@ -0,0 +1,94 @@
use std::sync::atomic::AtomicUsize;
use serde::{de::DeserializeOwned, Serialize};
pub(crate) mod deserialize;
pub(crate) mod serialize;
#[derive(serde::Serialize, serde::Deserialize, Default)]
pub(crate) struct HTMLData {
pub data: Vec<Vec<u8>>,
}
impl HTMLData {
pub(crate) fn push<T: Serialize>(&mut self, value: &T) {
let serialized = postcard::to_allocvec(value).unwrap();
self.data.push(serialized);
}
pub(crate) fn cursor(self) -> HTMLDataCursor {
HTMLDataCursor {
data: self.data,
index: AtomicUsize::new(0),
}
}
}
pub(crate) struct HTMLDataCursor {
data: Vec<Vec<u8>>,
index: AtomicUsize,
}
impl HTMLDataCursor {
pub fn take<T: DeserializeOwned>(&self) -> Option<T> {
let current = self.index.load(std::sync::atomic::Ordering::SeqCst);
if current >= self.data.len() {
return None;
}
let mut cursor = &self.data[current];
self.index.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Some(postcard::from_bytes(&mut cursor).unwrap())
}
}
#[test]
fn serialized_and_deserializes() {
use postcard::to_allocvec;
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
struct Data {
a: u32,
b: String,
bytes: Vec<u8>,
nested: Nested,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
struct Nested {
a: u32,
b: u16,
c: u8,
}
for x in 0..10usize {
for y in 0..10 {
let mut as_string: Vec<u8> = Vec::new();
let data = vec![
Data {
a: x as u32,
b: "hello".to_string(),
bytes: vec![0; x],
nested: Nested {
a: 1,
b: x as u16,
c: 3
},
};
y
];
serialize::serde_to_writable(&data, &mut as_string).unwrap();
println!("{:?}", as_string);
println!(
"original size: {}",
std::mem::size_of::<Data>() * data.len()
);
println!("serialized size: {}", to_allocvec(&data).unwrap().len());
println!("compressed size: {}", as_string.len());
let decoded: Vec<Data> = deserialize::serde_from_bytes(&as_string).unwrap();
assert_eq!(data, decoded);
}
}
}
@@ -0,0 +1,40 @@
use serde::Serialize;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
#[allow(unused)]
pub(crate) fn serde_to_writable<T: Serialize>(
value: &T,
write_to: &mut impl std::io::Write,
) -> std::io::Result<()> {
let serialized = postcard::to_allocvec(value).unwrap();
write_to.write_all(STANDARD.encode(serialized).as_bytes())?;
Ok(())
}
#[cfg(feature = "ssr")]
/// Encode data into a element. This is inteded to be used in the server to send data to the client.
pub(crate) fn encode_props_in_element<T: Serialize>(
data: &T,
write_to: &mut impl std::io::Write,
) -> std::io::Result<()> {
write_to.write_all(
r#"<meta hidden="true" id="dioxus-storage-props" data-serialized=""#.as_bytes(),
)?;
serde_to_writable(data, write_to)?;
write_to.write_all(r#"" />"#.as_bytes())
}
#[cfg(feature = "ssr")]
/// Encode data into a element. This is inteded to be used in the server to send data to the client.
pub(crate) fn encode_in_element(
data: &super::HTMLData,
write_to: &mut impl std::io::Write,
) -> std::io::Result<()> {
write_to.write_all(
r#"<meta hidden="true" id="dioxus-storage-data" data-serialized=""#.as_bytes(),
)?;
serde_to_writable(&data, write_to)?;
write_to.write_all(r#"" />"#.as_bytes())
}