use std::cmp::max;
pub struct WithLengthAndWidth<T> {
length: usize,
width: usize,
value: T,
}
pub enum RenderedCommon {
Empty,
Resolution,
Event(String),
Action {
name: String,
rendered: Box<WithLengthAndWidth<RenderedAny>>,
},
}
pub enum RenderedWide {
Common(RenderedCommon),
Wide(Vec<WithLengthAndWidth<RenderedLong>>),
}
pub enum RenderedLong {
Common(RenderedCommon),
Long(Vec<WithLengthAndWidth<RenderedWide>>),
}
pub enum RenderedAny {
Common(RenderedCommon),
Wide(Vec<WithLengthAndWidth<RenderedLong>>),
Long(Vec<WithLengthAndWidth<RenderedWide>>),
}
impl WithLengthAndWidth<RenderedWide> {
pub fn push_into(self, vec: &mut WithLengthAndWidth<Vec<WithLengthAndWidth<RenderedWide>>>) {
vec.length += self.length;
vec.width = max(vec.width, self.width);
vec.value.push(self);
}
pub fn any(self) -> WithLengthAndWidth<RenderedAny> {
self.map(RenderedWide::any)
}
}
impl WithLengthAndWidth<RenderedLong> {
pub fn push_into(self, vec: &mut WithLengthAndWidth<Vec<WithLengthAndWidth<RenderedLong>>>) {
vec.width += self.width;
vec.length = max(vec.length, self.length);
vec.value.push(self);
}
pub fn any(self) -> WithLengthAndWidth<RenderedAny> {
self.map(RenderedLong::any)
}
}
impl RenderedWide {
fn any(self) -> RenderedAny {
match self {
Self::Common(common) => RenderedAny::Common(common),
Self::Wide(vec) => RenderedAny::Wide(vec),
}
}
}
impl RenderedLong {
fn any(self) -> RenderedAny {
match self {
Self::Common(common) => RenderedAny::Common(common),
Self::Long(vec) => RenderedAny::Long(vec),
}
}
}
impl<A> WithLengthAndWidth<A> {
pub fn map<B>(self, f: impl FnOnce(A) -> B) -> WithLengthAndWidth<B> {
WithLengthAndWidth {
length: self.length,
width: self.width,
value: f(self.value),
}
}
pub fn length(&self) -> usize {
self.length
}
pub fn width(&self) -> usize {
self.width
}
pub fn value(&self) -> &A {
&self.value
}
}
impl<A: Default> Default for WithLengthAndWidth<A> {
fn default() -> Self {
Self {
length: 0,
width: 0,
value: Default::default(),
}
}
}
impl WithLengthAndWidth<RenderedAny> {
pub fn wrap(self, name: &str) -> WithLengthAndWidth<RenderedCommon> {
WithLengthAndWidth {
length: self.length,
width: self.width,
value: RenderedCommon::Action {
name: name.into(),
rendered: self.into(),
},
}
}
}
impl RenderedCommon {
pub fn empty() -> WithLengthAndWidth<Self> {
WithLengthAndWidth {
length: 0,
width: 0,
value: RenderedCommon::Empty,
}
}
pub fn resolution() -> WithLengthAndWidth<Self> {
WithLengthAndWidth {
length: 1,
width: 1,
value: RenderedCommon::Resolution,
}
}
pub fn event(event: &str) -> WithLengthAndWidth<Self> {
WithLengthAndWidth {
length: 0,
width: 0,
value: RenderedCommon::Event(event.into()),
}
}
}
impl RenderedCommon {
fn rectangles(self, vec: &mut Vec<(usize, usize)>, t: usize, c: usize) {
match self {
Self::Empty => {}
Self::Resolution => vec.push((t, c)),
Self::Event(_) => {}
Self::Action { rendered, .. } => rendered.rectangles(vec, t, c),
}
}
}
impl WithLengthAndWidth<RenderedAny> {
fn rectangles(self, vec: &mut Vec<(usize, usize)>, t: usize, c: usize) {
match self.value {
RenderedAny::Common(common) => common.rectangles(vec, t, c),
RenderedAny::Wide(rendereds) => {
Self::wide_rectangles(c, rendereds, vec, t);
}
RenderedAny::Long(rendereds) => {
Self::long_rectangles(t, rendereds, vec, c, self.width);
}
}
}
fn wide_rectangles(
c: usize,
rendereds: Vec<WithLengthAndWidth<RenderedLong>>,
vec: &mut Vec<(usize, usize)>,
t: usize,
) {
let mut c = c;
for rendered in rendereds.into_iter().map(|x| x.map(RenderedLong::any)) {
let rw = rendered.width;
rendered.rectangles(vec, t, c);
c += 2 * rw;
}
}
fn long_rectangles(
t: usize,
rendereds: Vec<WithLengthAndWidth<RenderedWide>>,
vec: &mut Vec<(usize, usize)>,
c: usize,
width: usize,
) {
let mut t = t;
for rendered in rendereds.into_iter().map(|x| x.map(RenderedWide::any)) {
let rl = rendered.length;
let rw = rendered.width;
rendered.rectangles(vec, t, c + (width - rw) / 2);
t += rl;
}
}
pub fn to_vec(self) -> Vec<(usize, usize)> {
let mut vec = Vec::new();
self.rectangles(&mut vec, 0, 0);
vec
}
}