use super::*;12/// Utility struct for the `when-then-otherwise` expression.3///4/// Represents the state of the expression after [when] is called.5///6/// In this state, `then` must be called to continue to finish the expression.7#[derive(Clone)]8pub struct When {9condition: Expr,10}1112/// Utility struct for the `when-then-otherwise` expression.13///14/// Represents the state of the expression after `when(...).then(...)` is called.15#[derive(Clone)]16pub struct Then {17condition: Expr,18statement: Expr,19}2021/// Utility struct for the `when-then-otherwise` expression.22///23/// Represents the state of the expression after an additional `when` is called.24///25/// In this state, `then` must be called to continue to finish the expression.26#[derive(Clone)]27pub struct ChainedWhen {28conditions: Vec<Expr>,29statements: Vec<Expr>,30}3132/// Utility struct for the `when-then-otherwise` expression.33///34/// Represents the state of the expression after an additional `then` is called.35#[derive(Clone)]36pub struct ChainedThen {37conditions: Vec<Expr>,38statements: Vec<Expr>,39}4041impl When {42/// Add a condition to the `when-then-otherwise` expression.43pub fn then<E: Into<Expr>>(self, expr: E) -> Then {44Then {45condition: self.condition,46statement: expr.into(),47}48}49}5051impl Then {52/// Attach a statement to the corresponding condition.53pub fn when<E: Into<Expr>>(self, condition: E) -> ChainedWhen {54ChainedWhen {55conditions: vec![self.condition, condition.into()],56statements: vec![self.statement],57}58}5960/// Define a default for the `when-then-otherwise` expression.61pub fn otherwise<E: Into<Expr>>(self, statement: E) -> Expr {62ternary_expr(self.condition, self.statement, statement.into())63}64}6566impl ChainedWhen {67pub fn then<E: Into<Expr>>(mut self, statement: E) -> ChainedThen {68self.statements.push(statement.into());69ChainedThen {70conditions: self.conditions,71statements: self.statements,72}73}74}7576impl ChainedThen {77/// Add another condition to the `when-then-otherwise` expression.78pub fn when<E: Into<Expr>>(mut self, condition: E) -> ChainedWhen {79self.conditions.push(condition.into());8081ChainedWhen {82conditions: self.conditions,83statements: self.statements,84}85}8687/// Define a default for the `when-then-otherwise` expression.88pub fn otherwise<E: Into<Expr>>(self, expr: E) -> Expr {89// we iterate the preds/ exprs last in first out90// and nest them.91//92// // this expr:93// when((col('x') == 'a')).then(1)94// .when(col('x') == 'b').then(2)95// .when(col('x') == 'c').then(3)96// .otherwise(4)97//98// needs to become:99// when((col('x') == 'a')).then(1) -100// .otherwise( |101// when(col('x') == 'b').then(2) - |102// .otherwise( | |103// pl.when(col('x') == 'c').then(3) | |104// .otherwise(4) | inner | outer105// ) | |106// ) _| _|107//108// by iterating LIFO we first create109// `inner` and then assign that to `otherwise`,110// which will be used in the next layer `outer`111//112113let conditions_iter = self.conditions.into_iter().rev();114let mut statements_iter = self.statements.into_iter().rev();115116let mut otherwise = expr.into();117118for e in conditions_iter {119otherwise = ternary_expr(120e,121statements_iter122.next()123.expect("expr expected, did you call when().then().otherwise?"),124otherwise,125);126}127128otherwise129}130}131132/// Start a `when-then-otherwise` expression.133pub fn when<E: Into<Expr>>(condition: E) -> When {134When {135condition: condition.into(),136}137}138139pub fn ternary_expr(predicate: Expr, truthy: Expr, falsy: Expr) -> Expr {140Expr::Ternary {141predicate: Arc::new(predicate),142truthy: Arc::new(truthy),143falsy: Arc::new(falsy),144}145}146147/// Compute `op(l, r)` (or equivalently `l op r`). `l` and `r` must have types compatible with the Operator.148pub fn binary_expr(l: Expr, op: Operator, r: Expr) -> Expr {149Expr::BinaryExpr {150left: Arc::new(l),151op,152right: Arc::new(r),153}154}155156157