Remove intermediary vecs/btreemaps for ordering on index
Diff
Cargo.lock | 2 +-
templates/index.html | 16 +++++++++-------
src/methods/index.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 48 insertions(+), 27 deletions(-)
@@ -1,6 +1,6 @@
version = 4
version = 3
[[package]]
name = "addr2line"
@@ -13,21 +13,21 @@
</thead>
<tbody>
{%- for (path, repositories) in repositories %}
{%- if let Some(path) = path %}
{%- for (path, repositories) in self.take_iter() %}
{%- if !path.is_empty() %}
<tr><td class="repo-section" colspan="4">{{ path }}</td></tr>
{%- endif -%}
{%- for repository in repositories %}
{% set repository = repository.get() %}
<tr class="{% if path.is_some() %}has-parent{% endif %}">
{% set repository = repository.1.get() %}
<tr class="{% if !path.is_empty() %}has-parent{% endif %}">
<td>
<a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
<a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
{{- repository.name -}}
</a>
</td>
<td>
<a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
<a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
{%- if let Some(description) = repository.description.as_ref() -%}
{{- description -}}
{%- else -%}
@@ -36,14 +36,14 @@
</a>
</td>
<td>
<a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
<a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
{%- if let Some(owner) = repository.owner.as_ref() -%}
{{- owner -}}
{%- endif -%}
</a>
</td>
<td>
<a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
<a href="/{% if !path.is_empty() %}{{ path }}/{% endif %}{{ repository.name }}">
<time datetime="{{ repository.last_modified|format_time }}" title="{{ repository.last_modified|format_time }}">
{{- repository.last_modified|timeago -}}
</time>
@@ -1,8 +1,12 @@
use std::{collections::BTreeMap, sync::Arc};
use std::{cell::RefCell, sync::Arc};
use anyhow::Context;
use askama::Template;
use axum::{response::IntoResponse, Extension};
use axum::{
response::{IntoResponse, Response},
Extension,
};
use itertools::{Either, Itertools};
use super::filters;
use crate::{
@@ -12,28 +16,45 @@
#[derive(Template)]
#[template(path = "index.html")]
pub struct View {
pub repositories: BTreeMap<Option<String>, Vec<YokedRepository>>,
pub struct View<
'a,
Group: Iterator<Item = (&'a String, &'a YokedRepository)>,
GroupIter: Iterator<Item = (&'a str, Group)>,
> {
pub repositories: RefCell<Either<GroupIter, std::iter::Empty<(&'a str, Group)>>>,
}
impl<'a, Group, GroupIter> View<'a, Group, GroupIter>
where
Group: Iterator<Item = (&'a String, &'a YokedRepository)>,
GroupIter: Iterator<Item = (&'a str, Group)>,
{
fn take_iter(&self) -> Either<GroupIter, std::iter::Empty<(&'a str, Group)>> {
self.repositories.replace(Either::Right(std::iter::empty()))
}
}
pub async fn handle(
Extension(db): Extension<Arc<rocksdb::DB>>,
) -> Result<impl IntoResponse, super::repo::Error> {
let mut repositories: BTreeMap<Option<String>, Vec<YokedRepository>> = BTreeMap::new();
) -> Result<Response, super::repo::Error> {
let fetched = tokio::task::spawn_blocking(move || Repository::fetch_all(&db))
.await
.context("Failed to join Tokio task")??;
for (k, v) in fetched {
let mut split: Vec<_> = k.split('/').collect();
split.pop();
let key = Some(split.join("/")).filter(|v| !v.is_empty());
let k = repositories.entry(key).or_default();
k.push(v);
}
Ok(into_response(View { repositories }))
let repositories = fetched
.iter()
.group_by(|(k, _)| memchr::memrchr(b'/', k.as_bytes()).map_or("", |idx| &k[..idx]));
Ok(into_response(View {
repositories: Either::Left(repositories.into_iter()).into(),
})
.into_response())
}