directwrite 0.1.4

A safe abstraction for interacting with DirectWrite, intended initially to be used with direct2d for easy text rendering.
Documentation
use enums::{FontStretch, FontStyle, FontWeight};
use error::DWriteError;
use font_collection::FontCollection;
use text_format::TextFormat;

use std::ptr;

use winapi::shared::winerror::SUCCEEDED;
use winapi::um::dwrite::{IDWriteFactory, IDWriteTextFormat};
use wio::com::ComPtr;
use wio::wide::ToWide;

pub struct TextFormatBuilder<'a> {
    factory: &'a IDWriteFactory,
    family: Option<&'a str>,
    collection: Option<&'a FontCollection>,
    weight: FontWeight,
    style: FontStyle,
    stretch: FontStretch,
    size: Option<f32>,
    locale: Option<&'a str>,
}

impl<'a> TextFormatBuilder<'a> {
    pub fn new(factory: &'a IDWriteFactory) -> TextFormatBuilder<'a> {
        TextFormatBuilder {
            factory,
            family: None,
            collection: None,
            weight: FontWeight::Normal,
            style: FontStyle::Normal,
            stretch: FontStretch::Normal,
            size: None,
            locale: None,
        }
    }

    pub fn build(self) -> Result<TextFormat, DWriteError> {
        unsafe {
            let family = self
                .family
                .expect("`family` must be specified")
                .to_wide_null();

            let collection = self
                .collection
                .map(|col| col.get_raw())
                .unwrap_or(ptr::null_mut());

            let size = self.size.expect("`size` must be specified");
            let locale = self.locale.unwrap_or("en-US").to_wide_null();

            let mut ptr: *mut IDWriteTextFormat = ptr::null_mut();
            let result = self.factory.CreateTextFormat(
                family.as_ptr(),
                collection,
                self.weight as u32,
                self.style as u32,
                self.stretch as u32,
                size,
                locale.as_ptr(),
                &mut ptr,
            );

            if SUCCEEDED(result) {
                Ok(TextFormat {
                    ptr: ComPtr::from_raw(ptr),
                })
            } else {
                Err(From::from(result))
            }
        }
    }

    pub fn with_family(mut self, family: &'a str) -> Self {
        self.family = Some(family);
        self
    }

    pub fn with_font_collection(mut self, collection: &'a FontCollection) -> Self {
        self.collection = Some(collection);
        self
    }

    pub fn with_weight(mut self, weight: FontWeight) -> Self {
        self.weight = weight;
        self
    }

    pub fn with_style(mut self, style: FontStyle) -> Self {
        self.style = style;
        self
    }

    pub fn with_stretch(mut self, stretch: FontStretch) -> Self {
        self.stretch = stretch;
        self
    }

    pub fn with_size(mut self, size: f32) -> Self {
        self.size = Some(size);
        self
    }

    pub fn with_locale(mut self, locale: &'a str) -> Self {
        self.locale = Some(locale);
        self
    }
}