use core::marker::PhantomData;
use serde::{Deserialize, Serialize};
use crate::File;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Project {
name: String,
root: File,
}
impl Project {
#[inline(always)]
pub fn builder() -> ProjectBuilder<WantsRoot> {
ProjectBuilder::default()
}
#[inline(always)]
pub fn name(&self) -> &str {
&self.name
}
#[inline(always)]
pub fn root(&self) -> &File {
&self.root
}
#[inline(always)]
fn uninit() -> Self {
Self { name: String::new(), root: File::uninit() }
}
}
pub struct ProjectBuilder<S> {
project: Project,
_state: PhantomData<S>,
}
impl Default for ProjectBuilder<WantsRoot> {
#[inline(always)]
fn default() -> Self {
Self::new(Project::uninit())
}
}
impl<S> ProjectBuilder<S> {
#[inline(always)]
fn change_state<NewState>(&mut self) -> &mut ProjectBuilder<NewState> {
unsafe { core::mem::transmute(self) }
}
#[inline(always)]
fn new(project: Project) -> Self {
Self { project, _state: PhantomData }
}
}
impl ProjectBuilder<WantsRoot> {
#[inline(always)]
pub fn root(&mut self, root: File) -> &mut ProjectBuilder<WithName> {
self.project.root = root;
self.change_state::<WithName>()
}
}
impl ProjectBuilder<WithName> {
#[inline(always)]
pub fn name<S>(&mut self, name: S) -> &mut ProjectBuilder<Done>
where
S: Into<String>,
{
self.project.name = name.into();
self.change_state::<Done>()
}
}
impl<S: CanBuild<Project>> ProjectBuilder<S> {
#[inline(always)]
pub fn build(&mut self) -> Project {
core::mem::replace(&mut self.project, Project::uninit())
}
}
pub struct Done;
pub struct WantsRoot;
pub struct WithName;
pub trait CanBuild<Inner>: Sealed {}
impl CanBuild<Project> for WithName {}
impl CanBuild<Project> for Done {}
impl Sealed for WithName {}
impl Sealed for Done {}
use sealed::Sealed;
mod sealed {
pub trait Sealed {}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{FileIdGenerator, PeerId};
#[test]
fn project_single_dir_two_children() {
let ids = FileIdGenerator::new();
let mut builder = Project::builder();
let peer_id = PeerId::new(1);
let root = File::build_directory()
.file_id(ids.next())
.name("foo")
.child(
File::build_document()
.file_id(ids.next())
.name("a.txt")
.peer_id(peer_id)
.text("")
.build(),
)
.child(
File::build_document()
.file_id(ids.next())
.name("b.txt")
.peer_id(peer_id)
.text("")
.build(),
)
.build();
let _project: Project = builder.root(root).name("foo").build();
}
}