#[cfg(not(any(
feature = "translations-eng",
feature = "translations-dut",
feature = "translations-fre",
feature = "translations-ger",
feature = "translations-hun",
feature = "translations-rus",
feature = "translations-slv",
feature = "translations-spa",
feature = "translations-swe"
)))]
compile_error!("no target languages selected (select at least one \"translations-XXX\" feature)");
use jmdict_enums::*;
use std::convert::TryInto;
use std::io::Write;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let opts = jmdict_traverse::Options {
is_db_minimal: cfg!(feature = "db-minimal"),
with_uncommon: cfg!(feature = "scope-uncommon"),
with_archaic: cfg!(feature = "scope-archaic"),
};
let mut omni: OmniBuffer = Default::default();
if cfg!(not(feature = "db-empty")) {
jmdict_traverse::process_dictionary(&mut omni, opts);
}
write_u32s(&path_to("entry_offsets.dat"), &omni.entry_offsets);
write_u32s(&path_to("payload.dat"), &omni.data);
std::fs::write(&path_to("strings.txt"), &omni.text).unwrap();
}
fn path_to(filename: &str) -> std::path::PathBuf {
let out_dir = std::env::var_os("OUT_DIR").unwrap();
std::path::Path::new(&out_dir).join(filename)
}
fn write_u32s(path: &std::path::Path, vals: &[u32]) {
let f = std::fs::File::create(&path).unwrap();
let mut f = std::io::BufWriter::new(f);
for val in vals {
f.write_all(&val.to_ne_bytes()).unwrap();
}
}
struct StoredRef {
start: u32,
end: u32,
}
impl From<(usize, usize)> for StoredRef {
fn from(val: (usize, usize)) -> Self {
let (start, end) = val;
let start = start.try_into().unwrap();
let end = end.try_into().unwrap();
Self { start, end }
}
}
#[derive(Default)]
struct OmniBuffer {
entry_offsets: Vec<u32>,
data: Vec<u32>,
text: String,
}
impl OmniBuffer {
pub fn push_str(&mut self, text: &str) -> StoredRef {
if text.is_empty() {
return (0, 0).into();
}
let start = self.text.len();
self.text.push_str(text);
let end = self.text.len();
(start, end).into()
}
pub fn push_data(&mut self, data: &[u32]) -> StoredRef {
if data.is_empty() {
return (0, 0).into();
}
let start = self.data.len();
self.data.extend(data);
(start, start + data.len()).into()
}
pub fn push_array<T: ToPayload>(&mut self, data: &[T]) -> StoredRef {
if data.is_empty() {
return (0, 0).into();
}
let size = T::size();
let mut repr = vec![0u32; data.len() * size];
for (idx, elem) in data.iter().enumerate() {
elem.encode_one(self, &mut repr[(idx * size)..((idx + 1) * size)]);
}
self.push_data(&repr)
}
}
impl jmdict_traverse::Visitor for OmniBuffer {
fn notify_data_file_path(&mut self, path: &str) {
println!("cargo:rerun-if-changed={}", &path);
}
fn process_entry(&mut self, entry: &jmdict_traverse::RawEntry) {
let size = jmdict_traverse::RawEntry::size();
let mut repr = vec![0u32; size];
entry.encode_one(self, &mut repr);
let r = self.push_data(&repr);
self.entry_offsets.push(r.start);
}
}
fn push_array<T: ToPayload>(buf: &mut Vec<u32>, omni: &mut OmniBuffer, array: &[T]) -> u32 {
if !array.is_empty() {
let size = T::size();
let mut repr = vec![0u32; array.len() * size];
for (idx, elem) in array.iter().enumerate() {
elem.encode_one(omni, &mut repr[(idx * size)..((idx + 1) * size)]);
}
buf.extend(repr);
}
buf.len() as u32
}
trait ToPayload {
fn size() -> usize;
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]);
}
macro_rules! enum_to_payload {
($t:ident) => {
impl ToPayload for $t {
fn size() -> usize {
1
}
fn encode_one(&self, _omni: &mut OmniBuffer, buf: &mut [u32]) {
buf[0] = self.to_u32();
}
}
};
}
enum_to_payload!(KanjiInfo);
enum_to_payload!(ReadingInfo);
enum_to_payload!(PartOfSpeech);
enum_to_payload!(SenseTopic);
enum_to_payload!(SenseInfo);
enum_to_payload!(Dialect);
impl ToPayload for jmdict_traverse::RawEntry<'_> {
fn size() -> usize {
4
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
let mut dbuf = Vec::new();
let offset1 = push_array(&mut dbuf, omni, &self.k_ele);
let offset2 = push_array(&mut dbuf, omni, &self.r_ele);
push_array(&mut dbuf, omni, &self.sense);
let r = omni.push_data(&dbuf);
buf[0] = r.start;
buf[1] = r.end;
buf[2] = offset1 + (offset2 << 16);
buf[3] = self.ent_seq;
}
}
impl ToPayload for jmdict_traverse::RawKanjiElement<'_> {
fn size() -> usize {
5
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
buf[0] = self.ke_pri.to_u32();
let r = omni.push_str(self.keb);
buf[1] = r.start;
buf[2] = r.end;
let r = omni.push_array(&self.ke_inf);
buf[3] = r.start;
buf[4] = r.end;
}
}
impl ToPayload for jmdict_traverse::RawReadingElement<'_> {
fn size() -> usize {
5
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
buf[0] = self.re_pri.to_u32();
let r = omni.push_str(self.reb);
buf[1] = r.start;
buf[2] = r.end;
let r = omni.push_array(&self.re_inf);
buf[3] = r.start;
buf[4] = r.end;
}
}
impl ToPayload for jmdict_traverse::RawSense<'_> {
fn size() -> usize {
5
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
let mut dbuf = Vec::new();
let offset1 = push_array(&mut dbuf, omni, &self.stagk);
let offset2 = push_array(&mut dbuf, omni, &self.stagr);
let offset3 = push_array(&mut dbuf, omni, &self.pos);
let offset4 = push_array(&mut dbuf, omni, &self.xref);
let offset5 = push_array(&mut dbuf, omni, &self.ant);
let offset6 = push_array(&mut dbuf, omni, &self.field);
let offset7 = push_array(&mut dbuf, omni, &self.misc);
let offset8 = push_array(&mut dbuf, omni, &self.s_inf);
let offset9 = push_array(&mut dbuf, omni, &self.lsource);
let offset10 = push_array(&mut dbuf, omni, &self.dial);
push_array(&mut dbuf, omni, &self.gloss);
let r = omni.push_data(&dbuf);
buf[0] = r.start;
buf[1] = r.end;
buf[2] = offset1 + (offset2 << 8) + (offset3 << 16) + (offset4 << 24);
buf[3] = offset5 + (offset6 << 8) + (offset7 << 16) + (offset8 << 24);
buf[4] = offset9 + (offset10 << 8);
}
}
impl ToPayload for jmdict_traverse::RawLSource<'_> {
fn size() -> usize {
4
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
let r = omni.push_str(self.text);
buf[0] = r.start;
buf[1] = r.end;
let r = omni.push_str(self.lang);
buf[2] = r.start;
buf[3] = r.end;
if self.is_partial {
buf[0] |= 0x10000000;
}
if self.is_wasei {
buf[0] |= 0x20000000;
}
}
}
impl ToPayload for jmdict_traverse::RawGloss<'_> {
fn size() -> usize {
2
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
let r = omni.push_str(self.text);
buf[0] = r.start | (self.lang.to_u32() << 28);
buf[1] = r.end | (self.g_type.to_u32() << 28);
}
}
impl<'a> ToPayload for &'a str {
fn size() -> usize {
2
}
fn encode_one(&self, omni: &mut OmniBuffer, buf: &mut [u32]) {
let r = omni.push_str(self);
buf[0] = r.start;
buf[1] = r.end;
}
}
impl ToPayload for u32 {
fn size() -> usize {
1
}
fn encode_one(&self, _omni: &mut OmniBuffer, buf: &mut [u32]) {
buf[0] = *self;
}
}