whydrogen 0.1.0

A slightly opinioated search query parser/lexer.
Documentation
// SPDX-FileContributor: Slatian
//
// SPDX-License-Identifier: LGPL-3.0-only

//! Keyword converters know which keywords and prefixes are part of your search syntax
//! and how to best encode them for your backend.
//!
//! This module hosts the [KeywordConverter] trait which you probably want to implement
//! yourself and two implementations for prototyping and debugging.

use std::marker::PhantomData;

/// Recognizes custom keywords and prefix charaters and allows you to implement things
/// like the `site:…` or bang `!…` syntax popular in search engines.
///
/// The KeywordConverter is intended to be implemented on a configurable struct
/// to allow for easier translation, while `K` is intended to be an enum
/// representing the keyword in a production system.
pub trait KeywordConverter<K> {

	/// Returns the appropritate `Sone(K)` if the given text is a valid keyword,
	/// oherwise `None`. For the `site:…` construct the given value would be `site`.
	///
	/// The default implementation always returns `None`.
	fn try_convert_keyword(&self, _text: &str) -> Option<K> {
		return None;
	}
	
	/// Returns the appropritate `Sone(K)` if the given character is a valid prefix,
	/// oherwise `None`. Only called for non-alphanumeric characters.
	///
	/// The default implementation always returns `None`.
	fn try_convert_prefix(&self, _prefix: char) -> Option<K> {
		return None;
	}
	
}

/// A [KeywordConverter] that can be used for prototyping or debugging that
/// just spits out the `String` representation of a keyword or prefix.
///
/// By default it accepts all keywords and no prefixes.
pub struct StringKeywordConverter {

	/// List of keywords that get accepted, if the list is empty
	/// the StringKeywordConverter accepts all keywords.
	pub keywords: Vec<String>,

	/// List of accepted prefixes.
	pub prefixes: Vec<char>,
}

impl StringKeywordConverter {

	/// Constructs a new, unconfigured StringKeywordConverter.
	pub fn new() -> Self {
		return Self{
			keywords: Vec::new(),
			prefixes: Vec::new(),
		}
	}

	/// Convenience function to add a keyword to the list of accepted keywords.
	pub fn add_key(&mut self, text: &str) {
		self.keywords.push(text.to_string());
	}

	/// Convenience function to add a prefix to the list of accepted prefixes.
	pub fn add_prefix(&mut self, pfx: char) {
		self.prefixes.push(pfx);
	}
}

impl KeywordConverter<String> for StringKeywordConverter {
	fn try_convert_keyword(&self, text: &str) -> Option<String> {
		let s = text.to_string();
		if self.keywords.len() == 0 {
			return Some(s);
		}
		if self.keywords.contains(&s) {
			return Some(s);
		}
		return None;
	}

	fn try_convert_prefix(&self, pfx: char) -> Option<String> {
		if self.prefixes.contains(&pfx) {
			return Some(pfx.to_string());
		}
		return None;
	}
}

/// A [KeywordConverter] that never accepts a keyword or prefix.
/// Useful for debugging and simple searches.
pub struct NullKeywordConverter<K> {
	phantom_keyword: PhantomData<K>,
}

impl<K> NullKeywordConverter<K> {

	/// Constructs a new NullKeywordConverter.
	pub fn new() -> Self {
		return Self {
			phantom_keyword: PhantomData,
		}
	}
}

impl<K> KeywordConverter<K> for NullKeywordConverter<K> {
	fn try_convert_keyword(&self, _text: &str) -> Option<K> {
		return None;
	}

	fn try_convert_prefix(&self, _pfx: char) -> Option<K> {
		return None;
	}
}