From b46069aa864553f27f304dd7a4ef7cc6f3b88fd1 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sun, 24 Sep 2023 14:08:56 +0800 Subject: [PATCH] refactor: improve the public interface by using triats --- src/lib.rs | 154 +++++++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 70 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 84a6535..1a1e6e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ use std::ffi::{CString, NulError}; use std::os::raw::c_uchar; +use crate::go::guess::GoGuess; use crate::go::slice::{GoSlice, ToGoSlice}; use crate::go::string::{GoString, ToGoString}; -use crate::go::guess::GoGuess; pub use go::guess::Guess; @@ -54,12 +54,19 @@ extern "C" { /// detection will be based on the filename. The function won't read the file, given an empty content. /// /// [Linguist.detect]: https://github.com/github/linguist/blob/aad49acc0624c70d654a8dce447887dbbc713c7a/lib/linguist.rb#L14-L49 -pub fn get_languages(filename: &str, content: &[u8]) -> Result, NulError> { - let c_filename = CString::new(filename).expect("Can't construct string"); - let c_content = CString::new(content).expect("Can't construct content string"); +pub fn get_languages, B: AsRef<[u8]>>( + filename: S, + content: B, +) -> Result, NulError> { + let c_filename = CString::new(filename.as_ref()).expect("Can't construct string"); + let c_content = CString::new(content.as_ref()).expect("Can't construct content string"); let mut go_result = GoSlice::default(); unsafe { - GetLanguages(c_filename.as_go_string(), c_content.as_go_slice(), &mut go_result); + GetLanguages( + c_filename.as_go_string(), + c_content.as_go_slice(), + &mut go_result, + ); Ok(Vec::from(go_result)) } } @@ -70,24 +77,23 @@ pub fn get_languages(filename: &str, content: &[u8]) -> Result, NulE /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_content(filename: &str, content: &[u8]) -> Result { - let c_filename = CString::new(filename)?; - let c_content = CString::new(content)?; +pub fn get_language_by_content, B: AsRef<[u8]>>( + filename: S, + content: B, +) -> Result { + let c_filename = CString::new(filename.as_ref())?; + let c_content = CString::new(content.as_ref())?; unsafe { - Ok( - Guess::from( - GetLanguageByContent( - c_filename.as_go_string(), - c_content.as_go_slice(), - ) - ) - ) + Ok(Guess::from(GetLanguageByContent( + c_filename.as_go_string(), + c_content.as_go_slice(), + ))) } } /// `get_language_extensions()` returns all extensions associated with the given language. -pub fn get_language_extensions(language: &str) -> Result, NulError> { - let c_language = CString::new(language)?; +pub fn get_language_extensions>(language: S) -> Result, NulError> { + let c_language = CString::new(language.as_ref())?; let mut go_result = GoSlice::default(); unsafe { GetLanguageExtensions(c_language.as_go_string(), &mut go_result); @@ -97,54 +103,54 @@ pub fn get_language_extensions(language: &str) -> Result, NulError> /// `get_language()` applies a sequence of strategies based on the given filename /// and content to find out the most probable language to return. -pub fn get_language(filename: &str, content: &[u8]) -> Result { - let c_filename = CString::new(filename)?; - let c_content = CString::new(content)?; - unsafe { - Ok( - GetLanguage( - c_filename.as_go_string(), - c_content.as_go_slice(), - ) - .to_string() - ) - } +pub fn get_language, B: AsRef<[u8]>>( + filename: S, + content: B, +) -> Result { + let c_filename = CString::new(filename.as_ref())?; + let c_content = CString::new(content.as_ref())?; + unsafe { Ok(GetLanguage(c_filename.as_go_string(), c_content.as_go_slice()).to_string()) } } /// `get_mime_type()` returns a MIME type of a given file based on its languages. -pub fn get_mime_type(path: &str, language: &str) -> Result { - let c_path = CString::new(path)?; - let c_language = CString::new(language)?; - unsafe { - Ok(GetMimeType(c_path.as_go_string(), c_language.as_go_string()).to_string()) - } +pub fn get_mime_type>(path: S, language: S) -> Result { + let c_path = CString::new(path.as_ref())?; + let c_language = CString::new(language.as_ref())?; + unsafe { Ok(GetMimeType(c_path.as_go_string(), c_language.as_go_string()).to_string()) } } - /// `get_language_by_extension()` returns detected language. /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_extension(filename: &str) -> Result { - let c_filename = CString::new(filename)?; - unsafe { Ok(Guess::from(GetLanguageByExtension(c_filename.as_go_string()))) } +pub fn get_language_by_extension>(filename: S) -> Result { + let c_filename = CString::new(filename.as_ref())?; + unsafe { + Ok(Guess::from(GetLanguageByExtension( + c_filename.as_go_string(), + ))) + } } /// `get_language_by_filename()` returns detected language. /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_filename(filename: &str) -> Result { - let c_filename = CString::new(filename)?; - unsafe { Ok(Guess::from(GetLanguageByFilename(c_filename.as_go_string()))) } +pub fn get_language_by_filename>(filename: S) -> Result { + let c_filename = CString::new(filename.as_ref())?; + unsafe { + Ok(Guess::from(GetLanguageByFilename( + c_filename.as_go_string(), + ))) + } } /// `get_language_by_modeline()` returns detected language. /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_modeline(content: &[u8]) -> Result { - let c_content = CString::new(content)?; +pub fn get_language_by_modeline>(content: B) -> Result { + let c_content = CString::new(content.as_ref())?; unsafe { Ok(Guess::from(GetLanguageByModeline(c_content.as_go_slice()))) } } @@ -152,8 +158,8 @@ pub fn get_language_by_modeline(content: &[u8]) -> Result { /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_shebang(content: &[u8]) -> Result { - let c_content = CString::new(content)?; +pub fn get_language_by_shebang>(content: B) -> Result { + let c_content = CString::new(content.as_ref())?; unsafe { Ok(Guess::from(GetLanguageByShebang(c_content.as_go_slice()))) } } @@ -161,67 +167,75 @@ pub fn get_language_by_shebang(content: &[u8]) -> Result { /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_vim_modeline(content: &[u8]) -> Result { - let c_content = CString::new(content)?; - unsafe { Ok(Guess::from(GetLanguageByVimModeline(c_content.as_go_slice()))) } +pub fn get_language_by_vim_modeline>(content: B) -> Result { + let c_content = CString::new(content.as_ref())?; + unsafe { + Ok(Guess::from(GetLanguageByVimModeline( + c_content.as_go_slice(), + ))) + } } /// `get_language_by_emacs_modeline()` returns detected language. /// /// If there are more than one possibles languages it returns the first language /// by alphabetically order and the `safe` field of `Guess` will be set to false. -pub fn get_language_by_emacs_modeline(content: &[u8]) -> Result { - let c_content = CString::new(content)?; - unsafe { Ok(Guess::from(GetLanguageByEmacsModeline(c_content.as_go_slice()))) } +pub fn get_language_by_emacs_modeline>(content: B) -> Result { + let c_content = CString::new(content.as_ref())?; + unsafe { + Ok(Guess::from(GetLanguageByEmacsModeline( + c_content.as_go_slice(), + ))) + } } /// `is_binary()` detects if data is a binary value based /// on this [code snippet](http://git.kernel.org/cgit/git/git.git/tree/xdiff-interface.c?id=HEAD#n198). -pub fn is_binary(data: &[u8]) -> Result { - let c_data = CString::new(data)?; +pub fn is_binary>(data: B) -> Result { + let c_data = CString::new(data.as_ref())?; unsafe { Ok(IsBinary(c_data.as_go_slice()) == 1) } } /// `is_configuration()` tells if filename is in one of the configuration languages. -pub fn is_configuration(path: &str) -> Result { - let c_path = CString::new(path)?; +pub fn is_configuration>(path: S) -> Result { + let c_path = CString::new(path.as_ref())?; unsafe { Ok(IsConfiguration(c_path.as_go_string()) == 1) } } /// `is_documentation()` returns whether or not path is a documentation path. -pub fn is_documentation(path: &str) -> Result { - let c_path = CString::new(path)?; +pub fn is_documentation>(path: S) -> Result { + let c_path = CString::new(path.as_ref())?; unsafe { Ok(IsDocumentation(c_path.as_go_string()) == 1) } } /// `is_dot_file()` returns whether or not path has dot as a prefix. -pub fn is_dot_file(path: &str) -> Result { - let c_path = CString::new(path)?; +pub fn is_dot_file>(path: S) -> Result { + let c_path = CString::new(path.as_ref())?; unsafe { Ok(IsDotFile(c_path.as_go_string()) == 1) } } /// `is_image()` tells if a given file is an image (PNG, JPEG or GIF format). -pub fn is_image(path: &str) -> Result { - let c_path = CString::new(path)?; +pub fn is_image>(path: S) -> Result { + let c_path = CString::new(path.as_ref())?; unsafe { Ok(IsImage(c_path.as_go_string()) == 1) } } /// `is_vendor()` returns whether or not path is a vendor path. -pub fn is_vendor(path: &str) -> Result { - let c_path = CString::new(path)?; +pub fn is_vendor>(path: S) -> Result { + let c_path = CString::new(path.as_ref())?; unsafe { Ok(IsVendor(c_path.as_go_string()) == 1) } } /// `is_generated()` returns whether the file with the given path and content /// is a generated file. -pub fn is_generated(path: &str, content: &[u8]) -> Result { - let c_path = CString::new(path)?; - let c_content = CString::new(content)?; +pub fn is_generated, B: AsRef<[u8]>>(path: S, content: B) -> Result { + let c_path = CString::new(path.as_ref())?; + let c_content = CString::new(content.as_ref())?; unsafe { Ok(IsGenerated(c_path.as_go_string(), c_content.as_go_slice()) == 1) } } /// `get_color()` returns the HTML color code of a given language. -pub fn get_color(language: &str) -> Result { - let c_language = CString::new(language)?; +pub fn get_color>(language: S) -> Result { + let c_language = CString::new(language.as_ref())?; unsafe { Ok(GetColor(c_language.as_go_string()).to_string()) } }