use std::fmt;
pub trait StringExtensions {
fn file_extension(&self) -> Option<String>;
fn remove_file_extension(&self) -> String;
fn url_extension(&self) -> Option<String>;
fn join_path(&self, relative: String) -> String;
fn hash_code<S: Into<String>>(&self, str: S) -> u32;
fn substitute(&self, values: Vec<String>) -> String;
}
impl StringExtensions for String {
fn file_extension(&self) -> Option<String> {
if let Some(dot) = self.rfind(".") {
Some(self[dot + 1..].to_string())
} else {
None
}
}
fn remove_file_extension(&self) -> String {
if let Some(dot) = self.rfind(".") {
self[..dot].to_string()
} else {
self.clone()
}
}
fn url_extension(&self) -> Option<String> {
let mut out = self.clone();
let question = self.rfind("?");
if let Some(question) = self.rfind("?") {
out = out[..question].to_string();
}
if let Some(slash) = self.rfind("/") {
out = out[slash + 1..].to_string();
}
out.file_extension()
}
fn join_path(&self, relative: String) -> String {
const SEP: char = '/'; let mut out = self.clone();
if let Some(last) = self.chars().last() {
if last != SEP {
out.push(SEP)
}
}
format!("{}{}", out, relative)
}
fn hash_code<S: Into<String>>(&self, str: S) -> u32 {
let mut code = 0;
let str: String = str.into();
if !str.is_empty() {
let chars = str.chars(); for ch in str.chars() {
code = 31 * code + ch.to_digit(10).unwrap();
}
}
code
}
fn substitute(&self, values: Vec<String>) -> String {
let mut out = String::from("");
for ii in 0..values.len() {
out = self.replace(format!("{{{}}}", ii).as_str(), values[ii].as_str());
}
out
}
}
impl StringExtensions for str {
fn file_extension(&self) -> Option<String> {
if let Some(dot) = self.rfind(".") {
Some(self[dot + 1..].to_string())
} else {
None
}
}
fn remove_file_extension(&self) -> String {
if let Some(dot) = self.rfind(".") {
self[..dot].to_string()
} else {
self.to_owned()
}
}
fn url_extension(&self) -> Option<String> {
let mut out = self.to_string();
if let Some(question) = out.rfind("?") {
out = out[..question].to_string();
}
if let Some(slash) = out.rfind("/") {
out = out[slash + 1..].to_string()
}
out.file_extension()
}
fn join_path(&self, relative: String) -> String {
const SEP: char = '/'; let mut out = self.to_string();
if let Some(last) = self.chars().last() {
if last != SEP {
out.push(SEP)
}
}
format!("{}{}", out, relative)
}
fn hash_code<S: Into<String>>(&self, str: S) -> u32 {
let mut code = 0;
let str: String = str.into();
if !str.is_empty() {
let chars = str.chars(); for ch in str.chars() {
code = 31 * code + ch.to_digit(10).unwrap();
}
}
code
}
fn substitute(&self, values: Vec<String>) -> String {
let mut out = String::from("");
for ii in 0..values.len() {
out = out.replace(format!("{{{}}}", ii).as_str(), values[ii].as_str());
}
out
}
}