use std::{cell::RefCell, rc::Rc}; use bitflags::bitflags; /// Represents various types of connection #[derive(Copy, Clone, PartialEq, Debug)] pub enum ConnectionType { /// Close connection after response Close, /// Keep connection alive after response KeepAlive, /// Connection is upgraded to different type Upgrade, } bitflags! { pub(crate) struct Flags: u8 { const CLOSE = 0b0000_0001; const KEEP_ALIVE = 0b0000_0010; const UPGRADE = 0b0000_0100; const EXPECT = 0b0000_1000; const NO_CHUNKING = 0b0001_0000; const CAMEL_CASE = 0b0010_0000; } } #[doc(hidden)] pub trait Head: Default + 'static { fn clear(&mut self); fn with_pool(f: F) -> R where F: FnOnce(&MessagePool) -> R; } pub struct Message { /// Rc here should not be cloned by anyone. /// It's used to reuse allocation of T and no shared ownership is allowed. head: Rc, } impl Message { /// Get new message from the pool of objects #[allow(clippy::new_without_default)] pub fn new() -> Self { T::with_pool(MessagePool::get_message) } } impl std::ops::Deref for Message { type Target = T; fn deref(&self) -> &Self::Target { self.head.as_ref() } } impl std::ops::DerefMut for Message { fn deref_mut(&mut self) -> &mut Self::Target { Rc::get_mut(&mut self.head).expect("Multiple copies exist") } } impl Drop for Message { fn drop(&mut self) { T::with_pool(|p| p.release(self.head.clone())) } } #[doc(hidden)] /// Request's objects pool pub struct MessagePool(RefCell>>); impl MessagePool { pub(crate) fn create() -> MessagePool { MessagePool(RefCell::new(Vec::with_capacity(128))) } /// Get message from the pool #[inline] fn get_message(&self) -> Message { if let Some(mut msg) = self.0.borrow_mut().pop() { // Message is put in pool only when it's the last copy. // which means it's guaranteed to be unique when popped out. Rc::get_mut(&mut msg) .expect("Multiple copies exist") .clear(); Message { head: msg } } else { Message { head: Rc::new(T::default()), } } } #[inline] /// Release message instance fn release(&self, msg: Rc) { let pool = &mut self.0.borrow_mut(); if pool.len() < 128 { pool.push(msg); } } }