use serde::{Deserialize, Serialize};
use std::str::FromStr;
use crate::types::{CacheControlEphemeral, TextCitation};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TextBlock {
#[serde(skip_serializing_if = "Option::is_none")]
pub citations: Option<Vec<TextCitation>>,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_control: Option<CacheControlEphemeral>,
}
impl TextBlock {
pub fn new<S: Into<String>>(text: S) -> Self {
Self { text: text.into(), citations: None, cache_control: None }
}
pub fn with_citations<S: Into<String>>(text: S, citations: Vec<TextCitation>) -> Self {
Self { text: text.into(), citations: Some(citations), cache_control: None }
}
pub fn with_cache_control(mut self, cache_control: CacheControlEphemeral) -> Self {
self.cache_control = Some(cache_control);
self
}
pub fn with_citation(mut self, citation: TextCitation) -> Self {
if let Some(citations) = &mut self.citations {
citations.push(citation);
} else {
self.citations = Some(vec![citation]);
}
self
}
pub fn citation_count(&self) -> usize {
self.citations.as_ref().map_or(0, |c| c.len())
}
pub fn has_citations(&self) -> bool {
self.citation_count() > 0
}
}
impl FromStr for TextBlock {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::new(s))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::CitationCharLocation;
use serde_json::{json, to_value};
#[test]
fn text_block_serialization() {
let text_block = TextBlock::new("This is some text content.");
let json = serde_json::to_value(&text_block).unwrap();
let expected = serde_json::json!({"text": "This is some text content."});
assert_eq!(json, expected);
}
#[test]
fn text_block_with_citations_serialization() {
let char_location = CitationCharLocation {
cited_text: "example text".to_string(),
document_index: 0,
document_title: Some("Document Title".to_string()),
end_char_index: 12,
start_char_index: 0,
};
let citation = TextCitation::CharLocation(char_location);
let text_block =
TextBlock::with_citations("This is some text content with a citation.", vec![citation]);
let json_value = serde_json::to_value(&text_block).unwrap();
assert!(json_value.is_object());
let obj = json_value.as_object().unwrap();
assert_eq!(
obj.get("text").unwrap().as_str().unwrap(),
"This is some text content with a citation."
);
assert!(obj.get("citations").unwrap().is_array());
let citations = obj.get("citations").unwrap().as_array().unwrap();
assert_eq!(citations.len(), 1);
let citation = &citations[0];
assert_eq!(citation.get("cited_text").unwrap().as_str().unwrap(), "example text");
assert_eq!(citation.get("document_index").unwrap().as_i64().unwrap(), 0);
assert_eq!(citation.get("document_title").unwrap().as_str().unwrap(), "Document Title");
assert_eq!(citation.get("end_char_index").unwrap().as_i64().unwrap(), 12);
assert_eq!(citation.get("start_char_index").unwrap().as_i64().unwrap(), 0);
assert_eq!(citation.get("type").unwrap().as_str().unwrap(), "char_location");
}
#[test]
fn deserialization() {
let json = serde_json::json!({
"text": "This is some text content.",
"type": "text"
});
let text_block: TextBlock = serde_json::from_value(json).unwrap();
assert_eq!(text_block.text, "This is some text content.");
assert!(text_block.citations.is_none());
}
#[test]
fn helper_methods() {
let text_block = TextBlock::new("Simple text");
assert_eq!(text_block.citation_count(), 0);
assert!(!text_block.has_citations());
let char_location = CitationCharLocation {
cited_text: "example text".to_string(),
document_index: 0,
document_title: Some("Document Title".to_string()),
end_char_index: 12,
start_char_index: 0,
};
let citation = TextCitation::CharLocation(char_location);
let text_block = TextBlock::with_citations("Text with citation", vec![citation]);
assert_eq!(text_block.citation_count(), 1);
assert!(text_block.has_citations());
}
#[test]
fn text_block_with_cache_control() {
let cache_control = CacheControlEphemeral::new();
let text_block = TextBlock::new("Sample text content").with_cache_control(cache_control);
let json = to_value(&text_block).unwrap();
assert_eq!(
json,
json!({
"text": "Sample text content",
"cache_control": {
"type": "ephemeral"
}
})
);
}
#[test]
fn text_block_with_citation() {
let citation = TextCitation::CharLocation(CitationCharLocation {
cited_text: "example text".to_string(),
document_index: 0,
document_title: Some("Document Title".to_string()),
end_char_index: 12,
start_char_index: 0,
});
let text_block = TextBlock::new("Sample text content").with_citation(citation);
let json = to_value(&text_block).unwrap();
assert_eq!(
json,
json!({
"text": "Sample text content",
"citations": [
{
"cited_text": "example text",
"document_index": 0,
"document_title": "Document Title",
"end_char_index": 12,
"start_char_index": 0,
"type": "char_location"
}
]
})
);
}
#[test]
fn from_str() {
let text_block = "Sample text content".parse::<TextBlock>().unwrap();
assert_eq!(text_block.text, "Sample text content");
}
}