Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"cot-cli",
"cot-codegen",
"cot-macros",
"cot-core",
# Examples
"examples/admin",
"examples/custom-error-pages",
Expand Down Expand Up @@ -75,6 +76,7 @@ clap-verbosity-flag = { version = "3", default-features = false }
clap_complete = "4"
clap_mangen = "0.2.31"
cot = { version = "0.4.0", path = "cot" }
cot_core = { version = "0.4.0", path = "cot-core" }
cot_codegen = { version = "0.4.0", path = "cot-codegen" }
cot_macros = { version = "0.4.0", path = "cot-macros" }
criterion = "0.8"
Expand Down
49 changes: 49 additions & 0 deletions cot-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[package]
name = "cot_core"
version = "0.4.0"
description = "The Rust web framework for lazy developers - framework core."
categories = ["web-programming", "web-programming::http-server", "network-programming"]
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
readme.workspace = true
authors.workspace = true

[lints]
workspace = true

[dependencies]
http.workspace = true
derive_more = { workspace = true, features = ["debug", "deref", "display", "from"] }
thiserror.workspace = true
serde.workspace = true
serde_json.workspace = true
backtrace.workspace = true
bytes.workspace = true
futures-core.workspace = true
http-body.workspace = true
http-body-util.workspace = true
sync_wrapper.workspace = true
axum.workspace = true
cot_macros.workspace = true
askama = { workspace = true, features = ["alloc"] }
tower-sessions.workspace = true
serde_path_to_error.workspace = true
indexmap.workspace = true
serde_html_form.workspace = true
form_urlencoded.workspace = true
tower.workspace = true
futures-util.workspace = true

[dev-dependencies]
async-stream.workspace = true
cot = { workspace = true, features = ["test"] }
futures.workspace = true
tokio.workspace = true

[features]
default = []
json = []
18 changes: 10 additions & 8 deletions cot/src/body.rs → cot-core/src/body.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! HTTP body type.
//!
//! This module provides the [`Body`] type for representing HTTP bodies,
//! supporting both fixed in-memory buffers and streaming data sources.

use std::error::Error as StdError;
use std::fmt::{Debug, Formatter};
use std::pin::Pin;
Expand All @@ -9,7 +14,7 @@ use http_body::{Frame, SizeHint};
use http_body_util::combinators::BoxBody;
use sync_wrapper::SyncWrapper;

use crate::error::error_impl::impl_into_cot_error;
use crate::error::impl_into_cot_error;
use crate::{Error, Result};

/// A type that represents an HTTP request or response body.
Expand All @@ -28,10 +33,10 @@ use crate::{Error, Result};
/// ```
#[derive(Debug)]
pub struct Body {
pub(crate) inner: BodyInner,
pub inner: BodyInner,
}

pub(crate) enum BodyInner {
pub enum BodyInner {
Fixed(Bytes),
Streaming(SyncWrapper<Pin<Box<dyn Stream<Item = Result<Bytes>> + Send>>>),
Axum(SyncWrapper<axum::body::Body>),
Expand Down Expand Up @@ -166,12 +171,12 @@ impl Body {
}

#[must_use]
pub(crate) fn axum(inner: axum::body::Body) -> Self {
pub fn axum(inner: axum::body::Body) -> Self {
Self::new(BodyInner::Axum(SyncWrapper::new(inner)))
}

#[must_use]
pub(crate) fn wrapper(inner: BoxBody<Bytes, Error>) -> Self {
pub fn wrapper(inner: BoxBody<Bytes, Error>) -> Self {
Self::new(BodyInner::Wrapper(inner))
}
}
Expand Down Expand Up @@ -261,9 +266,6 @@ impl_into_cot_error!(ReadRequestBody, BAD_REQUEST);

#[cfg(test)]
mod tests {
use std::pin::Pin;
use std::task::{Context, Poll};

use futures::stream;
use http_body::Body as HttpBody;

Expand Down
16 changes: 16 additions & 0 deletions cot-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Error handling types and utilities for Cot applications.
//!
//! This module provides error types, error handlers, and utilities for
//! handling various types of errors that can occur in Cot applications,
//! including 404 Not Found errors, uncaught panics, and custom error pages.

pub mod backtrace;
pub(crate) mod error_impl;
mod method_not_allowed;
mod not_found;
mod uncaught_panic;

pub use error_impl::{Error, impl_into_cot_error};
pub use method_not_allowed::MethodNotAllowed;
pub use not_found::{Kind as NotFoundKind, NotFound};
pub use uncaught_panic::UncaughtPanic;
13 changes: 7 additions & 6 deletions cot/src/error/backtrace.rs → cot-core/src/error/backtrace.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// inline(never) is added to make sure there is a separate frame for this
// function so that it can be used to find the start of the backtrace.
#[inline(never)]
pub(crate) fn __cot_create_backtrace() -> Backtrace {
#[must_use]
pub fn __cot_create_backtrace() -> Backtrace {
let mut backtrace = Vec::new();
let mut start = false;
backtrace::trace(|frame| {
Expand All @@ -21,19 +22,19 @@ pub(crate) fn __cot_create_backtrace() -> Backtrace {
}

#[derive(Debug, Clone)]
pub(crate) struct Backtrace {
pub struct Backtrace {
frames: Vec<StackFrame>,
}

impl Backtrace {
#[must_use]
pub(crate) fn frames(&self) -> &[StackFrame] {
pub fn frames(&self) -> &[StackFrame] {
&self.frames
}
}

#[derive(Debug, Clone)]
pub(crate) struct StackFrame {
pub struct StackFrame {
symbol_name: Option<String>,
filename: Option<String>,
lineno: Option<u32>,
Expand All @@ -42,15 +43,15 @@ pub(crate) struct StackFrame {

impl StackFrame {
#[must_use]
pub(crate) fn symbol_name(&self) -> String {
pub fn symbol_name(&self) -> String {
self.symbol_name
.as_deref()
.unwrap_or("<unknown>")
.to_string()
}

#[must_use]
pub(crate) fn location(&self) -> String {
pub fn location(&self) -> String {
if let Some(filename) = self.filename.as_deref() {
let mut s = filename.to_owned();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ impl Error {
}

#[must_use]
pub(crate) fn backtrace(&self) -> &CotBacktrace {
pub fn backtrace(&self) -> &CotBacktrace {
&self.repr.backtrace
}

Expand Down Expand Up @@ -319,6 +319,7 @@ impl From<Error> for askama::Error {
}
}

#[macro_export]
macro_rules! impl_into_cot_error {
($error_ty:ty) => {
impl From<$error_ty> for $crate::Error {
Expand All @@ -335,7 +336,7 @@ macro_rules! impl_into_cot_error {
}
};
}
pub(crate) use impl_into_cot_error;
pub use impl_into_cot_error;

#[derive(Debug, thiserror::Error)]
#[error("failed to render template: {0}")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl NotFound {
}

#[must_use]
pub(crate) fn router() -> Self {
pub fn router() -> Self {
Self::with_kind(Kind::FromRouter)
}

Expand Down
File renamed without changes.
25 changes: 17 additions & 8 deletions cot/src/handler.rs → cot-core/src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
//! Request handler traits and utilities.
//!
//! This module provides the [`RequestHandler`] trait, which is the core
//! abstraction for handling HTTP requests in Cot. It is automatically
//! implemented for async functions taking extractors and returning responses.

use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
Expand Down Expand Up @@ -48,14 +54,14 @@ pub trait RequestHandler<T = ()> {
fn handle(&self, request: Request) -> impl Future<Output = Result<Response>> + Send;
}

pub(crate) trait BoxRequestHandler {
pub trait BoxRequestHandler {
fn handle(
&self,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + '_>>;
}

pub(crate) fn into_box_request_handler<T, H: RequestHandler<T> + Send + Sync>(
pub fn into_box_request_handler<T, H: RequestHandler<T> + Send + Sync>(
handler: H,
) -> impl BoxRequestHandler {
struct Inner<T, H>(H, PhantomData<fn() -> T>);
Expand Down Expand Up @@ -142,6 +148,7 @@ macro_rules! impl_request_handler_from_request {
};
}

#[macro_export]
macro_rules! handle_all_parameters {
($name:ident) => {
$name!();
Expand Down Expand Up @@ -227,19 +234,21 @@ macro_rules! handle_all_parameters_from_request {
};
}

pub(crate) use handle_all_parameters;
pub use handle_all_parameters;

handle_all_parameters!(impl_request_handler);
handle_all_parameters_from_request!(impl_request_handler_from_request);

#[rustfmt::skip] // `wrap_comments` breaks local links
/// A wrapper around a handler that's used in
/// [`Bootstrapper`](cot::Bootstrapper).
/// [`Bootstrapper`](../../cot/project/struct.Bootstrapper.html).
///
/// It is returned by
/// [`Bootstrapper::into_bootstrapped_project`](cot::Bootstrapper::finish).
/// Typically, you don't need to interact with this type directly, except for
/// creating it in [`Project::middlewares`](cot::Project::middlewares) through
/// the [`RootHandlerBuilder::build`](cot::project::RootHandlerBuilder::build)
/// [`Bootstrapper::finish()`](../../cot/project/struct.Bootstrapper.html#method.finish).
/// Typically, you don't need to interact with this type directly, except
/// for creating it in
/// [`Project::middlewares()`](../../cot/project/trait.Project.html#method.middlewares) through the
/// [`RootHandlerBuilder::build()`](../../cot/project/struct.RootHandlerBuilder.html#method.build)
/// method.
///
/// # Examples
Expand Down
11 changes: 11 additions & 0 deletions cot-core/src/headers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! HTTP header constants.
//!
//! This module provides commonly used content type header values.

pub const HTML_CONTENT_TYPE: &str = "text/html; charset=utf-8";
pub const MULTIPART_FORM_CONTENT_TYPE: &str = "multipart/form-data";
pub const URLENCODED_FORM_CONTENT_TYPE: &str = "application/x-www-form-urlencoded";
#[cfg(feature = "json")]
pub const JSON_CONTENT_TYPE: &str = "application/json";
pub const PLAIN_TEXT_CONTENT_TYPE: &str = "text/plain; charset=utf-8";
pub const OCTET_STREAM_CONTENT_TYPE: &str = "application/octet-stream";
File renamed without changes.
File renamed without changes.
Loading
Loading