Skip to content

Instantly share code, notes, and snippets.

@pzol
Last active August 29, 2015 13:56
Show Gist options
  • Select an option

  • Save pzol/9039214 to your computer and use it in GitHub Desktop.

Select an option

Save pzol/9039214 to your computer and use it in GitHub Desktop.
#[allow(ctypes, dead_code)];
#[feature(globs)];
use std::str;
use std::libc::{ c_char };
pub type UChar = u16;
pub type UChar32 = i32;
#[deriving(Eq)]
pub enum UErrorCode {
ZERO_ERROR = 0,
BUFFER_OVERFLOW_ERROR = 15
}
pub struct UBreakIterator;
pub enum UBreakIteratorType {
UBRK_CHARACTER,
UBRK_WORD,
UBRK_LINE,
UBRK_SENTENCE,
UBRK_TITLE
}
pub static TRUE: u8 = 1u8;
pub static FALSE: u8 = 0u8;
pub static SENTINEL: UChar32 = -1;
mod icuio {
use super::*;
#[link(name = "icuio")]
extern "C" {
pub fn u_printf_u_52(patternSpecification: *UChar, ...) -> i32;
}
}
mod icui18n {
use super::*;
struct URegularExpression;
#[link(name = "icui18n")]
extern "C" {
pub fn uregex_split_52(regexp: *URegularExpression, destBuf: *mut UChar, destCapacity: i32, requiredCapacity: *i32, destFields: &[*UChar], destFieldsCapacity: i32, status: *mut UErrorCode) -> i32;
}
}
mod icuuc {
use super::*;
use std::libc::{ c_char };
#[link(name = "icuuc")]
extern "C" {
// http://icu-project.org/apiref/icu4c/ustring_8h.html
pub fn u_strToUpper_52(dest: *mut UChar, destCapacity: i32, src: *UChar, srcLength: i32, locale: *c_char, pErrorCode: *mut UErrorCode) -> i32;
pub fn u_strToLower_52(dest: *mut UChar, destCapacity: i32, src: *UChar, srcLength: i32, locale: *c_char, pErrorCode: *mut UErrorCode) -> i32;
pub fn u_strlen_52(s: *UChar) -> i32;
pub fn u_errorName_52(code: i32) -> *char;
pub fn u_strFromUTF8WithSub_52(dest: *mut UChar, destCapacity: i32, pDestLength: *mut i32, src: *c_char, srcLength: i32, subChar: UChar32, pNumSubstitutions: *mut i32, pErrorCode: *mut UErrorCode) -> *mut UChar;
pub fn u_strToUTF8WithSub_52(dest: *mut c_char, destCapacity: i32, pDestLength: *mut i32, src: *UChar, srcLength: i32, subChar: UChar32, pNumSubstitutions: *mut i32, pErrorCode: *mut UErrorCode) -> *mut UChar;
pub fn u_strToTitle_52(dest: *mut UChar, destCapacity: i32, src: *UChar, srcLength: i32, titleIter: *UBreakIterator, locale: *c_char, pErrorCode: *mut UErrorCode) -> i32;
pub fn u_strcat_52(dest: *mut UChar, src: *UChar) -> *mut UChar;
pub fn u_strtok_r_52(src: *mut UChar, delim: *UChar, saveState: *mut *mut UChar) -> *UChar;
pub fn u_tolower_52(c: UChar32) -> UChar32;
pub fn u_toupper_52(c: UChar32) -> UChar32;
}
}
#[inline]
pub fn to_upper(c: UChar32) -> UChar32 {
unsafe { icuuc::u_toupper_52(c) }
}
#[inline]
pub fn to_lower(c: UChar32) -> UChar32 {
unsafe { icuuc::u_tolower_52(c) }
}
// Adapters to the ICUUC versions, in case their signature changes. Also to hide the u_.*_52 and unsafe calls
#[inline]
pub fn strtok_r(src: *mut UChar, delim: *UChar, saveState: *mut *mut UChar) -> *UChar {
unsafe {
icuuc::u_strtok_r_52(src, delim, saveState)
}
}
#[inline]
pub fn strFromUTF8WithSub(dest: *mut UChar, destCapacity: i32, pDestLength: *mut i32, src: *c_char, srcLength: i32, subChar: UChar32, pNumSubstitutions: *mut i32, pErrorCode: *mut UErrorCode) -> *mut UChar {
unsafe {
icuuc::u_strFromUTF8WithSub_52(dest, destCapacity, pDestLength, src, srcLength, subChar, pNumSubstitutions, pErrorCode)
}
}
#[inline]
pub fn strToUTF8WithSub(dest: *mut c_char, destCapacity: i32, pDestLength: *mut i32, src: *UChar, srcLength: i32, subChar: UChar32, pNumSubstitutions: *mut i32, pErrorCode: *mut UErrorCode) -> *mut UChar {
unsafe {
icuuc::u_strToUTF8WithSub_52(dest, destCapacity, pDestLength, src, srcLength, subChar, pNumSubstitutions, pErrorCode)
}
}
#[inline]
pub fn strToLower(dest: *mut UChar, destCapacity: i32, src: *UChar, srcLength: i32, locale: *c_char, pErrorCode: *mut UErrorCode) -> i32 {
unsafe {
icuuc::u_strToLower_52(dest, destCapacity, src, srcLength, locale, pErrorCode)
}
}
#[inline]
pub fn strToUpper(dest: *mut UChar, destCapacity: i32, src: *UChar, srcLength: i32, locale: *c_char, pErrorCode: *mut UErrorCode) -> i32 {
unsafe {
icuuc::u_strToUpper_52(dest, destCapacity, src, srcLength, locale, pErrorCode)
}
}
#[inline]
pub fn strcat(dest: *mut UChar, src: *UChar) -> *mut UChar {
unsafe {
icuuc::u_strcat_52(dest, src)
}
}
#[inline]
pub fn strToTitle(dest: *mut UChar, destCapacity: i32, src: *UChar, srcLength: i32, titleIter: *UBreakIterator, locale: *c_char, pErrorCode: *mut UErrorCode) -> i32 {
unsafe {
icuuc::u_strToTitle_52(dest, destCapacity, src, srcLength, titleIter, locale, pErrorCode)
}
}
#[inline]
pub fn strlen(buf: *UChar) -> i32 {
unsafe {
icuuc::u_strlen_52(buf)
}
}
#[inline]
pub fn error_name(code: UErrorCode) -> ~str {
unsafe {
str::raw::from_c_str(icuuc::u_errorName_52(code as i32) as *i8)
}
}
#[inline]
pub fn success(code: UErrorCode) -> bool {
code == ZERO_ERROR
}
#[inline]
pub fn failure(code: UErrorCode) -> bool {
code != ZERO_ERROR
}
#[inline]
pub fn printf(buf: *UChar) {
unsafe {
icuio::u_printf_u_52(buf);
}
}
#[crate_id = "ustr#0.1"];
#[crate_type = "lib"];
#[license = "MIT"];
#[feature(globs)];
#[allow(dead_code)];
extern crate extra;
pub use ffi::*;
use std::{ fmt, ptr, vec, str };
mod ffi;
#[deriving(Eq, Clone)]
pub struct UString {
buf: ~[UChar] // UChar *ptr;
}
//////////////////////////////////// Traits ////////////////////////////////////
pub trait ToUString {
fn to_u(&self) -> UString;
}
pub trait UJoin {
fn join(&self, delim: &UString) -> UString;
}
impl UJoin for ~[UString] {
fn join(&self, delim: &UString) -> UString {
let mut it = self.iter();
match it.next() {
None => UString::new(),
Some(u) => {
let mut result = u.to_owned();
for word in it {
result = result.concat(delim).concat(word);
}
result
}
}
}
}
impl<'a> ToUString for &'a str {
fn to_u(&self) -> UString {
if self.len() == 0 {
return UString::new();
}
let cap = self.len() * 2;
let mut buf: ~[UChar] = vec::from_elem(cap, 0u16);
let mut pDestLength = 0;
let mut pNumSubstitutions: i32 = 0;
let mut error_code = ZERO_ERROR;
ffi::strFromUTF8WithSub(buf.as_mut_ptr(),
buf.capacity() as i32,
&mut pDestLength,
self.as_bytes().as_ptr() as *i8,
self.len() as i32,
SENTINEL,
&mut pNumSubstitutions,
&mut error_code);
assert!(success(error_code), ffi::error_name(error_code));
unsafe { buf.set_len(pDestLength as uint); }
UString { buf: buf }
}
}
impl fmt::Show for UString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{}", self.to_str())
}
}
impl Add<UString, UString> for UString {
fn add(&self, other: &UString) -> UString {
self.concat(other)
}
}
impl ToStr for UString {
fn to_str(&self) -> ~str {
let mut buf: ~[u8] = vec::from_elem(self.strlen() * 2, 0u8);
let mut pDestLength = 0;
let mut pNumSubstitutions: i32 = 0;
let mut error_code = ZERO_ERROR;
ffi::strToUTF8WithSub(buf.as_mut_ptr() as *mut i8,
buf.capacity() as i32,
&mut pDestLength,
self.buf.as_ptr(),
self.buf.len() as i32, // length, requires 0 termination of src
SENTINEL,
&mut pNumSubstitutions,
&mut error_code);
unsafe { buf.set_len(pDestLength as uint); }
str::from_utf8_owned(buf).unwrap_or(~"")
}
}
impl UString {
pub fn new() -> UString {
UString { buf: ~[]}
}
#[inline]
pub fn from_bytes(src: *UChar) -> UString {
let len = ffi::strlen(src);
let buf = unsafe { vec::raw::from_buf_raw(src, len as uint) };
UString { buf: buf }
}
pub fn as_ptr(&self) -> *UChar {
self.buf.as_ptr()
}
//////////////////////////////////// PUBLIC API ////////////////////////////////////
pub fn inspect(&self) -> ~str {
format!("UString \\{\"{:s}\", buf: {:?}\\}", self.to_str(), self.buf)
}
pub fn to_owned(&self) -> UString {
UString { buf: self.buf.to_owned() }
}
pub fn concat(&self, other: &UString) -> UString {
UString { buf: self.buf + other.buf }
}
pub fn concat_str(&self, other: &str) -> UString {
self.concat(&other.to_u())
}
pub fn chars<'a>(&'a self) -> vec::Items<'a, UChar> {
self.buf.iter()
}
// Returns a new copy of UString with all uppercase letters replaced with their uppercase counterparts.
pub fn upcase(&self) -> UString {
let buf = self.buf.map(|c| ffi::to_upper(*c as UChar32) as UChar);
UString { buf: buf }
}
// Returns a new copy of UString with all lowercase letters replaced with their uppercase counterparts.
pub fn downcase(&self) -> UString {
let buf = self.buf.map(|c| ffi::to_lower(*c as UChar32) as UChar);
UString { buf: buf }
}
pub fn titleize(&self) -> UString {
let mut buf: ~[UChar] = vec::from_elem(self.buf.len() + 1, 0u16);
let dummy = 0;
let mut error_code = ZERO_ERROR;
ffi::strToTitle(buf.as_mut_ptr(),
buf.capacity() as i32,
self.buf.as_ptr(),
self.buf.len() as i32,
ptr::null(), // break iterator
UString::null_locale(), // locale
&mut error_code);
assert!(success(error_code), ffi::error_name(error_code));
unsafe { buf.set_len(self.buf.len()) };
UString { buf: buf }
}
pub fn split(&self, delim: UString) -> ~[UString] {
let mut words = ~[];
let mut word = ~[];
for c in self.buf.iter() {
if delim.buf.contains(c) {
if word.len() > 0 {
words.push(UString { buf: word.clone() });
word = ~[];
}
} else {
word.push(*c);
}
}
if word.len() > 0 {
words.push(UString { buf: word });
}
words
}
pub fn starts_with(&self, prefix: &UString) -> bool {
self.buf.starts_with(prefix.buf)
}
pub fn ends_with(&self, postfix: &UString) -> bool {
self.buf.ends_with(postfix.buf)
}
pub fn slice(&self, start: uint, length: uint) -> UString {
let it = self.buf.iter().skip(start).take(length);
let buf = it.map(|e| e.clone()).to_owned_vec();
UString { buf: buf }
}
fn slice_pos(pos: int, len: uint) -> uint {
let ilen = len as int;
let result = match pos {
p if p < 0 && ilen + p < 0 => 0,
p if p < 0 => ilen + p,
p => p
} as uint;
result
}
pub fn slice_r(&self, start: int, the_end: int) -> UString {
let rstart = slice_pos(start, self.len());
let rend = slice_pos(the_end, self.len());
let mut pos = rstart;
let it = self.buf.iter().skip(rstart).take_while(|_| { pos = pos + 1; pos -1 <= rend } );
let buf = it.map(|e| e.clone()).to_owned_vec();
UString { buf: buf }
}
pub fn len(&self) -> uint {
self.buf.len()
}
fn null_locale() -> *i8 {
"".as_bytes().as_ptr() as *i8
}
fn strlen(&self) -> uint {
ffi::strlen(self.as_ptr()) as uint
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment