Coming from a bash scripting background, Rust’s syntax is mind boggling. The code from HttpServer...
to await?
is a single object. Trying to figure out how it works is going to be my first task.
I will return later with results in the replies.
// Create Http server with websocket support
let settings_bind = settings.clone();
HttpServer::new(move || {
let context = LemmyContext::create(
pool.clone(),
chat_server.to_owned(),
client.clone(),
activity_queue.to_owned(),
settings.to_owned(),
secret.to_owned(),
);
let rate_limiter = rate_limiter.clone();
App::new()
.wrap(middleware::Logger::default())
.app_data(Data::new(context))
// The routes
.configure(|cfg| api_routes::config(cfg, &rate_limiter))
.configure(|cfg| lemmy_apub::http::routes::config(cfg, &settings))
.configure(feeds::config)
.configure(|cfg| images::config(cfg, &rate_limiter))
.configure(nodeinfo::config)
.configure(|cfg| webfinger::config(cfg, &settings))
})
.bind((settings_bind.bind, settings_bind.port))?
.run()
.await?;
I’m going to tackle Rust from a variety of angles, one of which is by studying Lemmy.
So I think I figured a few things out.
HttpServer::new(move || )
is doing a few things. First,HttpServer
is calling a methodnew
whichmove
s the context (settings_bind
) into a closure (), which is kind of like a local-use function. The
||
denotes that no variables are being passed into the closure. Instead, the context is beingmove
d in so I guess it can be destroyed once the scope ofHttpServer
disappears.App::new()
must refer to a method ofHttpServer
but I haven’t investigated that yet. I suspect.run()
applies theApp
construct, whatever it is.HttpServer is calling a method new
new
isn’t a method andHttpServer
isn’t calling it.new
is an associated function of whateverHttpServer
is. Associated functions called new are usually used to create a new “instance” of a type they are associated with. SoType::new
will usually return aType
, aResult<Type, _>
, aOption<Type>
or something similar.Methods are functions that operate on a type, they always have
self
oror
&mut self
or whatever as their first parameter. You can omit that parameter if you use the “dot-syntax”.// So if you have let instance = Type::new(); // You can either write (like an associated function) Type::method(instance, other_parameter); // or (dot syntax) instance.method(other_parameter);
Instead, the context is being moved
The context (I assume you mean the variable in the closure) isn’t moved anywhere, the
move
keyword means, that the closure will take the ownership of all variables from the outer scope mentioned inside of it instead of borrowing or copying them.so I guess it can be destroyed once the scope of HttpServer disappears.
What can be destroyed? In most cases you don’t need to destroy (free/uninit) anything in rust, that is done “automatically” when something goes out of scope.
App::new() must refer to a method of HttpServer
It’s an associated function of
App
.I suspect .run() applies the App construct
It’s a method of whatever
.bind((settings_bind.bind, settings_bind.port))?
returns.You should really take @nutomic@lemmy.ml’s advice and read the book, play around a little bit and maybe do the rustlings course before you try understanding more complex programs. It’s not super hard but it will take some time, but feel free to ask here or in the rust forums if you feel stuck.
Initial observations
HttpServer::new(move || { [1] }).bind[2].run().await?;
is the basic structure. [1] consists of two parts,- Defining the
context
andrate_limiter
variables - Setting up something called
App:new()
We see
context
being loaded as.app_data
inApp::new()
, andrate_limiter
being loaded into the config.Then routes are added.
Part of what is unusual to me is defining variables within the server setup. But this may have something to do with the way Rust deals with variables. Since
context
has no meaning outside of this setup, better to use it here and throw it away once we’re done setting up theHttpServer
?Whereas
App::new()
dealt with Lemmy specific app configuration and behavior,.bind
appears to involve more genericHttpServer
configuration stuff [2], including the port to bind to.Then the whole thing
.run()
s, and then.await?
s for multithreading.- Defining the
This is a cool idea for a community