sms_splitter/
lib.rs

1//! # SMS Splitter
2//!
3//! [![Documentation](https://img.shields.io/badge/docs-0.1.9-4d76ae?style=for-the-badge)](https://docs.rs/sms_splitter)
4//! [![Version](https://img.shields.io/crates/v/sms_splitter?style=for-the-badge)](https://crates.io/crates/sms_splitter)
5//! [![License](https://img.shields.io/crates/l/sms_splitter?style=for-the-badge)](https://crates.io/crates/sms_splitter)
6//!
7//! An SMS message splitter with support for both GSM and Unicode written in Rust.
8//! GSM support is limited to GSM 03.38 with the extension table (see the [Wikipedia article](https://en.wikipedia.org/wiki/GSM_03.38#GSM_7_bit_default_alphabet_and_extension_table_of_3GPP_TS_23.038_.2F_GSM_03.38))
9//!
10//! ## Installation
11//!
12//! ```bash
13//! cargo add sms_splitter
14//! ```
15//!
16//! ## Usage
17//!
18//! ```rust
19//! use sms_splitter::SplitSms;
20//!
21//! fn main(){
22//!     let info = SplitSms::default().split("Hello World!".to_string());
23//!     println!("{:#?}", info);
24//! }
25//! ```
26//! <!-- out put -->
27//! ```text
28//! SplitSmsResult {
29//!     character_set: "GSM",
30//!     parts: [
31//!         SplitterPart {
32//!             content: "Hello World!",
33//!             length: 12,
34//!             bytes: 12,
35//!         },
36//!     ],
37//!     bytes: 12,
38//!     length: 12,
39//!     remaining_in_part: 148,
40//! }
41//! ```
42//!
43//! # Credits
44//!
45//! A lot of the code in this package was based on Codesleuth [`split-sms`](https://github.com/Codesleuth/split-sms).
46//!
47pub mod gsm_splitter;
48pub mod gsm_validator;
49pub mod splitter_options;
50pub mod splitter_result;
51pub mod unicode_splitter;
52// use
53use splitter_options::SplitterOptions;
54use splitter_result::{SplitterPart, SplitterResult};
55
56#[derive(Debug)]
57pub struct SplitSms {
58    options: SplitterOptions,
59}
60
61impl Default for SplitSms {
62    fn default() -> Self {
63        SplitSms::new(SplitterOptions::default())
64    }
65}
66
67impl SplitSms {
68    pub fn new(options: SplitterOptions) -> SplitSms {
69        SplitSms { options }
70    }
71
72    fn calculate_remaining(
73        &self,
74        parts: &Vec<SplitterPart>,
75        single_bytes: usize,
76        multi_bytes: usize,
77        char_bytes: usize,
78    ) -> usize {
79        let mut max = multi_bytes;
80        if parts.len() == 1 {
81            max = single_bytes;
82        }
83        (max - parts[parts.len() - 1].bytes) / char_bytes
84    }
85
86    fn validate_message(&self, message: String) -> bool {
87        if self.options.support_shift_tables {
88            return gsm_validator::GsmValidator::new().validate_message_with_shift_table(message);
89        }
90        gsm_validator::GsmValidator::new().validate_message(message)
91    }
92
93    pub fn split(&self, message: String) -> SplitSmsResult {
94        let is_gsm = self.validate_message(message.clone());
95        let split_result: SplitterResult;
96        let single_bytes: usize;
97        let multi_bytes: usize;
98        let char_bytes: usize;
99        let character_set: String;
100        if is_gsm {
101            split_result = gsm_splitter::GsmSplitter::new(SplitterOptions::new(
102                self.options.support_shift_tables,
103                self.options.summary,
104            ))
105            .split(message);
106            single_bytes = 160;
107            multi_bytes = 153;
108            char_bytes = 1;
109            character_set = "GSM".to_string();
110        } else {
111            split_result = unicode_splitter::UnicodeSplitter::new(SplitterOptions::new(
112                self.options.support_shift_tables,
113                self.options.summary,
114            ))
115            .split(message);
116            single_bytes = 140;
117            multi_bytes = 134;
118            char_bytes = 2;
119            character_set = "Unicode".to_string();
120        }
121        let remaining_in_part =
122            self.calculate_remaining(&split_result.parts, single_bytes, multi_bytes, char_bytes);
123        SplitSmsResult::new(
124            character_set,
125            split_result.parts,
126            split_result.total_bytes,
127            split_result.total_length,
128            remaining_in_part,
129        )
130    }
131}
132
133#[derive(Debug)]
134pub struct SplitSmsResult {
135    pub character_set: String,
136    pub parts: Vec<SplitterPart>,
137    pub bytes: usize,
138    pub length: usize,
139    pub remaining_in_part: usize,
140}
141
142impl SplitSmsResult {
143    pub fn new(
144        character_set: String,
145        parts: Vec<SplitterPart>,
146        bytes: usize,
147        length: usize,
148        remaining_in_part: usize,
149    ) -> SplitSmsResult {
150        SplitSmsResult {
151            character_set,
152            parts,
153            bytes,
154            length,
155            remaining_in_part,
156        }
157    }
158}
159
160impl Clone for SplitSmsResult {
161    fn clone(&self) -> Self {
162        SplitSmsResult {
163            character_set: self.character_set.clone(),
164            parts: self.parts.clone(),
165            bytes: self.bytes,
166            length: self.length,
167            remaining_in_part: self.remaining_in_part,
168        }
169    }
170}