Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
m4tx committed Aug 1, 2024
1 parent bd6ae75 commit 3e6d708
Show file tree
Hide file tree
Showing 16 changed files with 451 additions and 83 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"flareon-orm",
# Examples
"examples/hello-world",
"examples/todo-list",
]
resolver = "2"

Expand All @@ -15,13 +16,16 @@ edition = "2021"
license = "MIT OR Apache-2.0"

[workspace.dependencies]
askama = "0.12.1"
async-trait = "0.1.80"
axum = "0.7.5"
bytes = "1.6.1"
chrono = { version = "0.4.38", features = ["serde"] }
clap = { version = "4.5.8", features = ["derive", "env"] }
derive_builder = "0.20.0"
env_logger = "0.11.3"
flareon = { path = "flareon" }
flareon_macros = { path = "flareon-macros" }
indexmap = "2.2.6"
itertools = "0.13.0"
log = "0.4.22"
Expand Down
5 changes: 2 additions & 3 deletions examples/hello-world/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::sync::Arc;

use flareon::prelude::{
Body, Error, FlareonApp, FlareonProject, Request, Response, Route, StatusCode,
};
use flareon::prelude::{Body, Error, FlareonApp, FlareonProject, Request, Response, StatusCode};
use flareon::router::Route;

fn return_hello(_request: Request) -> Result<Response, Error> {
Ok(Response::new_html(
Expand Down
12 changes: 12 additions & 0 deletions examples/todo-list/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "example-todo-list"
version = "0.1.0"
publish = false
description = "TODO List - Flareon example."
edition = "2021"

[dependencies]
askama = "0.12.1"
flareon = { path = "../../flareon" }
tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
env_logger = "0.11.5"
73 changes: 73 additions & 0 deletions examples/todo-list/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::sync::Arc;

use askama::Template;
use flareon::prelude::{
Body, Error, FlareonApp, FlareonProject, Request, Response, Route, StatusCode,
};

#[derive(Form)]
struct TodoForm {
title: String,
}

#[derive(Debug)]
struct TodoItem {
id: u32,
title: String,
}

#[derive(Debug, Template)]
#[template(path = "index.html")]
struct IndexTemplate {
todo_items: Vec<TodoItem>,
}

fn index(_request: Request) -> Result<Response, Error> {
let index_template = IndexTemplate {
todo_items: vec![
TodoItem {
id: 1,
title: "Buy milk".to_string(),
},
TodoItem {
id: 2,
title: "Buy eggs".to_string(),
},
],
};
let rendered = index_template.render().unwrap();

Ok(Response::new_html(
StatusCode::OK,
Body::fixed(rendered.as_bytes().to_vec()),
))
}

fn add_todo(request: Request) -> Result<Response, Error> {
let todo_form = TodoForm::from_request(&request).unwrap();

// TODO add to global list

Ok(Response::new_html(
StatusCode::OK,
Body::fixed("redirect is not implemented yet".as_bytes().to_vec()),
))
}

#[tokio::main]
async fn main() {
env_logger::init();

let todo_app = FlareonApp::builder()
.urls([Route::with_handler("/", Arc::new(Box::new(index)))])
.urls([Route::with_handler("/add", Arc::new(Box::new(add_todo)))])
.build()
.unwrap();

let todo_project = FlareonProject::builder()
.register_app_with_views(todo_app, "")
.build()
.unwrap();

flareon::run(todo_project, "127.0.0.1:8000").await.unwrap();
}
23 changes: 23 additions & 0 deletions examples/todo-list/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODO List</title>
</head>
<body>
<h1>TODO List</h1>
<form id="todo-form">
<input type="text" id="todo-input" placeholder="Enter a new TODO" required>
<button type="submit">Add TODO</button>
</form>
<ul id="todo-list">
{% for todo in todo_items %}
<li>
<span>{{ todo.title }}</span>
<button onclick="removeTodoItem(this)">Remove</button>
</li>
{% endfor %}
</ul>
</body>
</html>
15 changes: 15 additions & 0 deletions flareon-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,19 @@ description = "Modern web framework focused on speed and ease of use - macros."
[lib]
proc-macro = true

[[test]]
name = "tests"
path = "tests/compile_tests.rs"

[dependencies]
darling = "0.20.10"
proc-macro-crate = "3.1.0"
proc-macro2 = "1.0.86"
proc-macro2-diagnostics = "0.10.1"
quote = "1.0.36"
syn = { version = "2.0.72", features = ["full"] }

[dev-dependencies]
flareon.workspace = true
serde.workspace = true
trybuild = { version = "1.0.99", features = ["diff"] }
44 changes: 44 additions & 0 deletions flareon-macros/src/form.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::any::{Any, TypeId};

use darling::{FromDeriveInput, FromField, FromMeta};
use proc_macro2::Ident;

pub fn form_for_struct(ast: syn::DeriveInput) -> proc_macro2::TokenStream {
let opts = match MyTraitOpts::from_derive_input(&ast) {
Ok(val) => val,
Err(err) => {
return err.write_errors();
}
};

for field in opts.data.take_struct().unwrap().fields {
println!("{:#?}", field);
}

// ast.data
// println!("{:#?}", opts);
proc_macro2::TokenStream::new()
}

#[derive(Debug, FromDeriveInput)]
#[darling(attributes(my_crate), forward_attrs(allow, doc, cfg))]
pub struct MyTraitOpts {
ident: syn::Ident,
attrs: Vec<syn::Attribute>,
data: darling::ast::Data<darling::util::Ignored, Field>,
}

#[derive(Debug, Clone, FromField)]
pub struct Field {
ident: Option<Ident>,
ty: syn::Type,
}

fn get_form_field_for_field(field: &Field) -> () {
// let xd: String = "xd";
//
// // check if string
// if field.ty == syn::parse_quote!(String) {
// println!("String");
// }
}
13 changes: 10 additions & 3 deletions flareon-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
mod form;

use darling::FromDeriveInput;
use proc_macro::TokenStream;
use syn::parse_macro_input;

use crate::form::form_for_struct;

#[proc_macro]
pub fn flareon(_input: TokenStream) -> TokenStream {
unimplemented!()
#[proc_macro_derive(Form)]
pub fn derive_form(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as syn::DeriveInput);
form_for_struct(ast).into()
}
5 changes: 5 additions & 0 deletions flareon-macros/tests/compile_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[test]
fn test_derive_form() {
let t = trybuild::TestCases::new();
t.pass("tests/ui/derive_form.rs");
}
10 changes: 10 additions & 0 deletions flareon-macros/tests/ui/derive_form.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use flareon_macros::Form;

#[derive(Debug, Form)]
struct MyForm {
name: String,
name2: std::string::String,
age: u32,
}

fn main() {}
2 changes: 2 additions & 0 deletions flareon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ license.workspace = true
description = "Modern web framework focused on speed and ease of use."

[dependencies]
askama.workspace = true
async-trait.workspace = true
axum.workspace = true
bytes.workspace = true
derive_builder.workspace = true
indexmap.workspace = true
log.workspace = true
regex.workspace = true
thiserror.workspace = true
tokio.workspace = true
81 changes: 5 additions & 76 deletions flareon/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod prelude;
pub mod router;
pub mod templates;

use std::fmt::{Debug, Formatter};
use std::io::Read;
Expand All @@ -10,6 +12,7 @@ use bytes::Bytes;
use derive_builder::Builder;
use indexmap::IndexMap;
use log::info;
use router::{Route, Router};
use thiserror::Error;

pub type StatusCode = axum::http::StatusCode;
Expand All @@ -19,42 +22,6 @@ pub trait RequestHandler {
async fn handle(&self, request: Request) -> Result<Response, Error>;
}

#[derive(Clone, Debug)]
pub struct Router {
urls: Vec<Route>,
}

impl Router {
#[must_use]
pub fn with_urls<T: Into<Vec<Route>>>(urls: T) -> Self {
Self { urls: urls.into() }
}

async fn route(&self, request: Request, request_path: &str) -> Result<Response, Error> {
for route in &self.urls {
if request_path.starts_with(&route.url) {
let request_path = &request_path[route.url.len()..];
match &route.view {
RouteInner::Handler(handler) => return handler.handle(request).await,
RouteInner::Router(router) => {
return Box::pin(router.route(request, request_path)).await
}
}
}
}

unimplemented!("404 handler is not implemented yet")
}
}

#[async_trait]
impl RequestHandler for Router {
async fn handle(&self, request: Request) -> Result<Response, Error> {
let path = request.uri().path().to_owned();
self.route(request, &path).await
}
}

#[async_trait]
impl<T> RequestHandler for T
where
Expand Down Expand Up @@ -100,48 +67,12 @@ impl FlareonAppBuilder {
}
}

#[derive(Clone)]
pub struct Route {
url: String,
view: RouteInner,
}

impl Route {
#[must_use]
pub fn with_handler<T: Into<String>>(
url: T,
view: Arc<Box<dyn RequestHandler + Send + Sync>>,
) -> Self {
Self {
url: url.into(),
view: RouteInner::Handler(view),
}
}

#[must_use]
pub fn with_router<T: Into<String>>(url: T, router: Router) -> Self {
Self {
url: url.into(),
view: RouteInner::Router(router),
}
}
}

#[derive(Clone)]
enum RouteInner {
Handler(Arc<Box<dyn RequestHandler + Send + Sync>>),
Router(Router),
}

impl Debug for Route {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.view {
RouteInner::Handler(_) => f.debug_tuple("Handler").field(&"handler(...)").finish(),
RouteInner::Router(router) => f.debug_tuple("Router").field(router).finish(),
}
}
}

pub type Request = axum::extract::Request;

type HeadersMap = IndexMap<String, String>;
Expand Down Expand Up @@ -230,10 +161,8 @@ impl FlareonProjectBuilder {
#[must_use]
pub fn register_app_with_views(&mut self, app: FlareonApp, url_prefix: &str) -> &mut Self {
let new = self;
new.urls.push(Route::with_handler(
url_prefix,
Arc::new(Box::new(app.router.clone())),
));
new.urls
.push(Route::with_router(url_prefix, app.router.clone()));
new.apps.push(app);
new
}
Expand Down
3 changes: 2 additions & 1 deletion flareon/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub use crate::router::Route;
pub use crate::{
Body, Error, FlareonApp, FlareonProject, Request, RequestHandler, Response, Route, StatusCode,
Body, Error, FlareonApp, FlareonProject, Request, RequestHandler, Response, StatusCode,
};
Loading

0 comments on commit 3e6d708

Please sign in to comment.