yoga 0.5.0

Rust bindings for Facebook's Yoga, a Flexbox layout engine
Documentation
use yoga::{get_node_ref_context, MeasureMode, NodeRef, Size};

const WIDTH_PER_CHAR: f32 = 10.0;
const HEIGHT_PER_CHAR: f32 = 10.0;

#[allow(dead_code)]
pub extern "C" fn intrinsic_measure_function(
    raw_node: NodeRef,
    width: f32,
    width_mode: MeasureMode,
    height: f32,
    height_mode: MeasureMode,
) -> Size {
    let context = get_node_ref_context(&raw_node);

    let text: &str = context
        .and_then(|ctx| {
            let s: Option<&String> = ctx.downcast_ref();
            s.map(|s| s.as_ref())
        })
        .unwrap_or("");

    let measured_width = match width_mode {
        MeasureMode::Exactly => width,
        MeasureMode::AtMost => (text.len() as f32 * WIDTH_PER_CHAR).min(width),
        MeasureMode::Undefined => text.len() as f32 * WIDTH_PER_CHAR,
    };

    let measured_height = match height_mode {
        MeasureMode::Exactly => height,
        MeasureMode::AtMost => {
            calculate_height(text, measured_width.max(get_widest_word_width(text))).min(height)
        },
        MeasureMode::Undefined => {
            calculate_height(text, measured_width.max(get_widest_word_width(text)))
        },
    };

    Size { width: measured_width, height: measured_height }
}

fn get_widest_word_width(text: &str) -> f32 {
    let widest_word_length = text.split(" ").map(|part| part.len()).max().unwrap_or(0);
    widest_word_length as f32 * WIDTH_PER_CHAR
}

fn calculate_height(text: &str, measured_width: f32) -> f32 {
    if text.len() as f32 * WIDTH_PER_CHAR <= measured_width {
        return HEIGHT_PER_CHAR;
    }

    let mut lines = 1;
    let mut current_line_length = 0.0;
    for word in text.split(" ") {
        let word_width = word.len() as f32 * WIDTH_PER_CHAR;
        if word_width > measured_width {
            if current_line_length > 0.0 {
                lines += 1;
            }
            lines += 1;
            current_line_length = 0.0;
        } else if current_line_length + word_width <= measured_width {
            current_line_length += word_width + WIDTH_PER_CHAR;
        } else {
            lines += 1;
            current_line_length = word_width + WIDTH_PER_CHAR;
        }
    }

    let lines = if current_line_length == 0.0 { lines - 1 } else { lines };

    lines as f32 * HEIGHT_PER_CHAR
}