559 lines
23 KiB
Rust
559 lines
23 KiB
Rust
|
use crate::prelude::*;
|
||
|
use anyhow::{Context, Result};
|
||
|
use assetpath::AssetPath;
|
||
|
|
||
|
use quick_xml::{events::Event, Reader};
|
||
|
|
||
|
use std::borrow::Cow;
|
||
|
use std::str::from_utf8;
|
||
|
use std::str::FromStr;
|
||
|
use std::{convert::TryFrom, io::BufRead, sync::Arc};
|
||
|
|
||
|
use super::buttoninfo::ButtonInfo;
|
||
|
use super::gridinfo::GridInfo;
|
||
|
use super::iconinfo::IconInfo;
|
||
|
use super::labelinfo::LabelInfo;
|
||
|
use super::multi_line_labelinfo::MultiLineLabelInfo;
|
||
|
use super::multi_line_text_field_info::MultiLineTextFieldInfo;
|
||
|
use super::progressbar_info::ProgressBarInfo;
|
||
|
use super::rootinfo::RootInfo;
|
||
|
use super::textfieldinfo::TextFieldInfo;
|
||
|
use super::uiinfoelement::UiInfoElement;
|
||
|
|
||
|
pub struct Validator {
|
||
|
reference_width: Option<u32>,
|
||
|
reference_height: Option<u32>,
|
||
|
layer: Option<i32>,
|
||
|
|
||
|
root: Root,
|
||
|
}
|
||
|
|
||
|
pub struct Root {
|
||
|
pub children: Vec<Arc<GridInfo>>,
|
||
|
}
|
||
|
|
||
|
enum StartResult {
|
||
|
Grid(GridInfo),
|
||
|
Button(ButtonInfo),
|
||
|
Label(LabelInfo),
|
||
|
MultiLineLabel(MultiLineLabelInfo),
|
||
|
MultiLineTextField(MultiLineTextFieldInfo),
|
||
|
Icon(IconInfo),
|
||
|
ProgressBar(ProgressBarInfo),
|
||
|
TextField(TextFieldInfo),
|
||
|
Root(RootInfo),
|
||
|
}
|
||
|
|
||
|
enum CurrentElement {
|
||
|
Grid(Arc<GridInfo>),
|
||
|
Button(Arc<ButtonInfo>),
|
||
|
Label(Arc<LabelInfo>),
|
||
|
MultiLineLabel(Arc<MultiLineLabelInfo>),
|
||
|
MultiLineTextField(Arc<MultiLineTextFieldInfo>),
|
||
|
Icon(Arc<IconInfo>),
|
||
|
ProgressBar(Arc<ProgressBarInfo>),
|
||
|
TextField(Arc<TextFieldInfo>),
|
||
|
Root,
|
||
|
None,
|
||
|
}
|
||
|
|
||
|
impl Validator {
|
||
|
pub fn from_str(gui_handler: &Arc<GuiHandler>, s: &str) -> Result<Validator> {
|
||
|
Self::_new(gui_handler, Reader::from_str(s))
|
||
|
}
|
||
|
|
||
|
pub fn new(gui_handler: &Arc<GuiHandler>, path: &AssetPath) -> Result<Validator> {
|
||
|
Self::_new(
|
||
|
gui_handler,
|
||
|
Reader::from_file(path.full_path()).with_context(|| path.full_path())?,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
fn _new<T: BufRead>(gui_handler: &Arc<GuiHandler>, mut reader: Reader<T>) -> Result<Validator> {
|
||
|
// removes white spaces in texts
|
||
|
reader.trim_text(true);
|
||
|
|
||
|
// <tag/> into <tag></tag>
|
||
|
reader.expand_empty_elements(true);
|
||
|
|
||
|
// validate closing tags
|
||
|
reader.check_end_names(true);
|
||
|
|
||
|
let mut buf = Vec::new();
|
||
|
|
||
|
let mut reference_width = None;
|
||
|
let mut reference_height = None;
|
||
|
let mut layer = None;
|
||
|
|
||
|
let mut root = Root {
|
||
|
children: Vec::new(),
|
||
|
};
|
||
|
|
||
|
let mut current_element = CurrentElement::None;
|
||
|
|
||
|
'outer: loop {
|
||
|
match reader.read_event_into(&mut buf) {
|
||
|
Ok(Event::Start(ref e)) => {
|
||
|
let start_result = Self::process_start(gui_handler, e, ¤t_element)?;
|
||
|
|
||
|
match start_result {
|
||
|
StartResult::Root(root_info) => {
|
||
|
reference_width = root_info.reference_width;
|
||
|
reference_height = root_info.reference_height;
|
||
|
layer = root_info.ui_layer;
|
||
|
|
||
|
current_element = CurrentElement::Root;
|
||
|
}
|
||
|
StartResult::Grid(mut grid_info) => {
|
||
|
if let CurrentElement::Grid(ref current_info) = current_element {
|
||
|
grid_info.parent = Some(Arc::downgrade(current_info));
|
||
|
}
|
||
|
|
||
|
let arc_info = Arc::new(grid_info);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref current_info) => current_info
|
||
|
.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::Grid(arc_info.clone())),
|
||
|
CurrentElement::Root => root.children.push(arc_info.clone()),
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
}
|
||
|
|
||
|
current_element = CurrentElement::Grid(arc_info);
|
||
|
}
|
||
|
StartResult::Button(button_info) => {
|
||
|
let arc_info = Arc::new(button_info);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::Button(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::Button(arc_info);
|
||
|
}
|
||
|
StartResult::Label(label_info) => {
|
||
|
let arc_info = Arc::new(label_info);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::Label(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::Label(arc_info);
|
||
|
}
|
||
|
StartResult::MultiLineLabel(multi_line_label_info) => {
|
||
|
let arc_info = Arc::new(multi_line_label_info);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::MultiLineLabel(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::MultiLineLabel(arc_info);
|
||
|
}
|
||
|
StartResult::MultiLineTextField(multi_line_text_field_info) => {
|
||
|
let arc_info = Arc::new(multi_line_text_field_info);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::MultiLineTextField(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::MultiLineTextField(arc_info);
|
||
|
}
|
||
|
StartResult::Icon(icon_info) => {
|
||
|
let arc_info = Arc::new(icon_info);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::Icon(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::Icon(arc_info);
|
||
|
}
|
||
|
StartResult::ProgressBar(progress_bar) => {
|
||
|
let arc_info = Arc::new(progress_bar);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::ProgressBar(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::ProgressBar(arc_info);
|
||
|
}
|
||
|
StartResult::TextField(text_field) => {
|
||
|
let arc_info = Arc::new(text_field);
|
||
|
|
||
|
match current_element {
|
||
|
CurrentElement::Grid(ref grid) => {
|
||
|
grid.children
|
||
|
.write()
|
||
|
.unwrap()
|
||
|
.push(UiInfoElement::TextField(arc_info.clone()));
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
};
|
||
|
|
||
|
current_element = CurrentElement::TextField(arc_info);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Ok(Event::End(ref e)) => {
|
||
|
let next_element = match current_element {
|
||
|
CurrentElement::Root => CurrentElement::None,
|
||
|
CurrentElement::None => {
|
||
|
return Err(anyhow::Error::msg(format!(
|
||
|
"Unexpected tag: {}",
|
||
|
from_utf8(e.name().into_inner())?
|
||
|
)));
|
||
|
}
|
||
|
CurrentElement::Grid(ref grid) => match grid.parent {
|
||
|
Some(ref weak_parent) => match weak_parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
},
|
||
|
None => CurrentElement::Root,
|
||
|
},
|
||
|
CurrentElement::Button(ref button) => match button.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
},
|
||
|
CurrentElement::Label(ref label) => match label.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
},
|
||
|
CurrentElement::MultiLineLabel(ref multi_line_label) => {
|
||
|
match multi_line_label.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
}
|
||
|
}
|
||
|
CurrentElement::MultiLineTextField(ref multi_line_text_field) => {
|
||
|
match multi_line_text_field.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
}
|
||
|
}
|
||
|
CurrentElement::Icon(ref icon) => match icon.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
},
|
||
|
CurrentElement::ProgressBar(ref progress_bar) => {
|
||
|
match progress_bar.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
}
|
||
|
}
|
||
|
CurrentElement::TextField(ref text_field) => {
|
||
|
match text_field.parent.upgrade() {
|
||
|
Some(arc_parent) => CurrentElement::Grid(arc_parent.clone()),
|
||
|
None => return Err(anyhow::Error::msg("Invalid parent reference")),
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
current_element = next_element;
|
||
|
}
|
||
|
Ok(Event::Text(ref e)) => match current_element {
|
||
|
CurrentElement::Root => {
|
||
|
return Err(anyhow::Error::msg("Text inside root not allowed"))
|
||
|
}
|
||
|
CurrentElement::None => {
|
||
|
return Err(anyhow::Error::msg("Text outside root not allowed"))
|
||
|
}
|
||
|
CurrentElement::Grid(_) => {
|
||
|
return Err(anyhow::Error::msg("Text inside grid not allowed"))
|
||
|
}
|
||
|
CurrentElement::Icon(ref icon) => {
|
||
|
*icon.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
CurrentElement::Button(ref button) => {
|
||
|
*button.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
CurrentElement::Label(ref label) => {
|
||
|
*label.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
CurrentElement::MultiLineLabel(ref multi_line_label) => {
|
||
|
*multi_line_label.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
CurrentElement::MultiLineTextField(ref multi_line_text_field) => {
|
||
|
*multi_line_text_field.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
CurrentElement::ProgressBar(ref progress_bar) => {
|
||
|
*progress_bar.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
CurrentElement::TextField(ref text_field) => {
|
||
|
*text_field.text.write().unwrap() = e.unescape()?.to_string();
|
||
|
}
|
||
|
},
|
||
|
Ok(Event::Eof) => match current_element {
|
||
|
CurrentElement::None => break 'outer,
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
|
||
|
Err(e) => return Err(anyhow::Error::new(e)),
|
||
|
|
||
|
_ => (),
|
||
|
}
|
||
|
|
||
|
buf.clear();
|
||
|
}
|
||
|
|
||
|
Ok(Validator {
|
||
|
reference_width,
|
||
|
reference_height,
|
||
|
layer,
|
||
|
|
||
|
root,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
fn process_start<'a>(
|
||
|
gui_handler: &Arc<GuiHandler>,
|
||
|
element: &quick_xml::events::BytesStart<'a>,
|
||
|
handle: &CurrentElement,
|
||
|
) -> Result<StartResult> {
|
||
|
Ok(match element.name().into_inner() {
|
||
|
b"grid" => match handle {
|
||
|
CurrentElement::None => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::Button(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::Label(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::MultiLineLabel(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::MultiLineTextField(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::Icon(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::ProgressBar(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::TextField(_) => {
|
||
|
return Err(anyhow::Error::msg("Wrong element in parser"));
|
||
|
}
|
||
|
CurrentElement::Root => match GridInfo::new(element.attributes()) {
|
||
|
Ok(grid) => StartResult::Grid(grid),
|
||
|
Err(msg) => return Err(msg),
|
||
|
},
|
||
|
CurrentElement::Grid(_) => match GridInfo::new(element.attributes()) {
|
||
|
Ok(grid) => StartResult::Grid(grid),
|
||
|
Err(msg) => return Err(msg),
|
||
|
},
|
||
|
},
|
||
|
b"button" => match handle {
|
||
|
CurrentElement::Grid(grid) => {
|
||
|
match ButtonInfo::new(gui_handler, element.attributes(), grid) {
|
||
|
Ok(button) => StartResult::Button(button),
|
||
|
Err(msg) => return Err(msg),
|
||
|
}
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"label" => match handle {
|
||
|
CurrentElement::Grid(grid) => match LabelInfo::new(element.attributes(), grid) {
|
||
|
Ok(label) => StartResult::Label(label),
|
||
|
Err(msg) => return Err(msg),
|
||
|
},
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"multi_line_label" => match handle {
|
||
|
CurrentElement::Grid(grid) => {
|
||
|
match MultiLineLabelInfo::new(element.attributes(), grid) {
|
||
|
Ok(label) => StartResult::MultiLineLabel(label),
|
||
|
Err(msg) => return Err(msg),
|
||
|
}
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"multi_line_textfield" => match handle {
|
||
|
CurrentElement::Grid(grid) => {
|
||
|
match MultiLineTextFieldInfo::new(element.attributes(), grid) {
|
||
|
Ok(text_field) => StartResult::MultiLineTextField(text_field),
|
||
|
Err(msg) => return Err(msg),
|
||
|
}
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"root" => match handle {
|
||
|
CurrentElement::None => match RootInfo::new(element.attributes()) {
|
||
|
Ok(root) => StartResult::Root(root),
|
||
|
Err(msg) => return Err(msg),
|
||
|
},
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"icon" => match handle {
|
||
|
CurrentElement::Grid(grid) => match IconInfo::new(element.attributes(), grid) {
|
||
|
Ok(icon) => StartResult::Icon(icon),
|
||
|
Err(msg) => return Err(msg),
|
||
|
},
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"progressbar" => match handle {
|
||
|
CurrentElement::Grid(grid) => {
|
||
|
match ProgressBarInfo::new(element.attributes(), grid) {
|
||
|
Ok(progress_bar) => StartResult::ProgressBar(progress_bar),
|
||
|
Err(msg) => return Err(msg),
|
||
|
}
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
b"textfield" => match handle {
|
||
|
CurrentElement::Grid(grid) => {
|
||
|
match TextFieldInfo::new(element.attributes(), grid) {
|
||
|
Ok(text_field) => StartResult::TextField(text_field),
|
||
|
Err(msg) => return Err(msg),
|
||
|
}
|
||
|
}
|
||
|
_ => return Err(anyhow::Error::msg("Wrong element in parser")),
|
||
|
},
|
||
|
_ => {
|
||
|
return Err(anyhow::Error::msg(format!(
|
||
|
"Unexpected tag: {}",
|
||
|
from_utf8(element.name().into_inner())?
|
||
|
)))
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
pub fn root(&self) -> &Root {
|
||
|
&self.root
|
||
|
}
|
||
|
|
||
|
pub fn dimensions(&self) -> (Option<u32>, Option<u32>) {
|
||
|
(self.reference_width, self.reference_height)
|
||
|
}
|
||
|
|
||
|
pub fn layer(&self) -> Option<i32> {
|
||
|
self.layer
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn str_into<'a, T>(cow: Cow<'a, [u8]>) -> Result<T>
|
||
|
where
|
||
|
T: FromStr,
|
||
|
{
|
||
|
let string = cow_to_str(cow);
|
||
|
|
||
|
match string.parse::<T>() {
|
||
|
Ok(number) => Ok(number),
|
||
|
Err(_) => Err(anyhow::Error::msg(format!(
|
||
|
"failed parsing value: {}",
|
||
|
string
|
||
|
))),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn cow_to_fill_type<'a>(cow: Cow<'a, [u8]>) -> FillTypeInfo {
|
||
|
let text = cow_to_str(cow);
|
||
|
|
||
|
match Color::try_from(text.as_str()) {
|
||
|
Ok(color) => FillTypeInfo::Color(color),
|
||
|
Err(_) => FillTypeInfo::Image(AssetPath::from(text)),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn cow_to_button_select_mode<'a>(cow: Cow<'a, [u8]>) -> Result<ButtonSelectMode> {
|
||
|
let text = cow_to_str(cow);
|
||
|
|
||
|
match text.as_str() {
|
||
|
"none" => Ok(ButtonSelectMode::None),
|
||
|
"bigger" => Ok(ButtonSelectMode::Bigger),
|
||
|
_ => Err(anyhow::Error::msg(format!(
|
||
|
"failed parsing value: {}",
|
||
|
text
|
||
|
))),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn cow_to_text_alignment<'a>(cow: Cow<'a, [u8]>) -> Result<TextAlignment> {
|
||
|
let text = cow_to_str(cow);
|
||
|
|
||
|
TextAlignment::try_from(text)
|
||
|
}
|
||
|
|
||
|
pub fn str_to_vert_align<'a>(cow: Cow<'a, [u8]>) -> Result<VerticalAlign> {
|
||
|
let string = cow_to_str(cow);
|
||
|
|
||
|
match string.as_str() {
|
||
|
"top" => Ok(VerticalAlign::Top),
|
||
|
"middle" => Ok(VerticalAlign::Middle),
|
||
|
"bottom" => Ok(VerticalAlign::Bottom),
|
||
|
_ => Err(anyhow::Error::msg(format!(
|
||
|
"failed parsing value: {}",
|
||
|
string
|
||
|
))),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn str_to_hori_align<'a>(cow: Cow<'a, [u8]>) -> Result<HorizontalAlign> {
|
||
|
let string = cow_to_str(cow);
|
||
|
|
||
|
match string.as_str() {
|
||
|
"left" => Ok(HorizontalAlign::Left),
|
||
|
"middle" => Ok(HorizontalAlign::Middle),
|
||
|
"right" => Ok(HorizontalAlign::Right),
|
||
|
_ => Err(anyhow::Error::msg(format!(
|
||
|
"failed parsing value: {}",
|
||
|
string
|
||
|
))),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn handle_function_suffix(fname: &str) -> String {
|
||
|
if fname.ends_with("()") {
|
||
|
str::replace(fname, "()", "")
|
||
|
} else {
|
||
|
fname.to_string()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn cow_to_str<'a>(cow: Cow<'a, [u8]>) -> String {
|
||
|
let u8s: &[u8] = &cow.to_owned();
|
||
|
from_utf8(u8s).unwrap().to_string()
|
||
|
}
|
||
|
|
||
|
pub fn cow_to_path<'a>(cow: Cow<'a, [u8]>) -> AssetPath {
|
||
|
AssetPath::from(cow_to_str(cow))
|
||
|
}
|