genie-sys 0.1.1

A rust binding for `Genie` (A Open Source MPEG-G Codec).
#include "lib.h"
#include <fstream>
#include <iostream>
#include <string>
#include "genie/format/fasta/exporter.h"
#include "genie/format/fastq/exporter.h"
#include "genie/format/fastq/importer.h"
#include "genie/format/mgrec/exporter.h"
#include "genie/format/mgrec/importer.h"
#include "genie/module/default-setup.h"
#include "genie/util/make-unique.h"

namespace geniesys {

std::string file_extension(const std::string& path) {
    auto pos = path.find_last_of('.');
    std::string ext = path.substr(pos + 1);
    for (auto& c : ext) {
        c = static_cast<char>(std::tolower(c));
    }
    return ext;
}

void convert_fastq(rust::String input_file, rust::String output_file, size_t threads) {
    UTILS_DIE_IF(input_file.empty(), "input_file must be non-empty!");
    UTILS_DIE_IF(output_file.empty(), "output_file must be non-empty!");

    std::string file1(input_file.c_str());
    std::string file2(output_file.c_str());
    std::unique_ptr<std::ifstream> file1_ptr;
    std::unique_ptr<std::ofstream> file2_ptr;
    std::istream* s1 = &std::cin;
    std::ostream* o1 = &std::cout;
    auto flow = genie::module::buildDefaultConverter(threads);

#ifdef DEBUG
    std::cout << "pwd: " << std::filesystem::current_path() << std::endl;
    std::cout << "input_file: " << file1 << std::endl;
    std::cout << "output_file: " << file2 << std::endl;
#endif

    if (file1.substr(0, 2) != "-.") {
        file1_ptr = genie::util::make_unique<std::ifstream>(file1, std::ifstream::in);
        UTILS_DIE_IF(file1_ptr->fail(), "Failed to open input_file!");
        s1 = file1_ptr.get();
    }

    if (file2.substr(0, 2) != "-.") {
        file2_ptr = genie::util::make_unique<std::ofstream>(file2, std::ofstream::binary | std::ofstream::app);
        UTILS_DIE_IF(file2_ptr->fail(), "Failed to open output_file!");
        o1 = file2_ptr.get();
    }

    flow->addImporter(genie::util::make_unique<genie::format::fastq::Importer>(BLOCKSIZE, *s1));
    flow->addExporter(genie::util::make_unique<genie::format::mgrec::Exporter>(*o1));
    flow->run();

    if (file1_ptr) file1_ptr->close();
    if (file2_ptr) file2_ptr->close();
};

void convert_fastq(rust::String input_file, rust::String sup_file, rust::String output_file, size_t threads) {
    UTILS_DIE_IF(input_file.empty(), "input_file must be non-empty!");
    UTILS_DIE_IF(sup_file.empty(), "sup_file must be non-empty!");
    UTILS_DIE_IF(output_file.empty(), "output_file must be non-empty!");

    std::string file1 = input_file.c_str();
    std::string file2 = sup_file.c_str();
    std::string file3 = output_file.c_str();
    std::unique_ptr<std::ifstream> file1_ptr;
    std::unique_ptr<std::ifstream> file2_ptr;
    std::unique_ptr<std::ofstream> file3_ptr;
    std::istream* s1 = &std::cin;
    std::ostream* o1 = &std::cout;
    auto flow = genie::module::buildDefaultConverter(threads);

#ifdef DEBUG
    std::cout << "pwd: " << std::filesystem::current_path() << std::endl;
    std::cout << "input_file: " << file1 << std::endl;
    std::cout << "sup_file: " << file2 << std::endl;
    std::cout << "output_file: " << file3 << std::endl;
#endif

    if (file1.substr(0, 2) != "-.") {
        file1_ptr = genie::util::make_unique<std::ifstream>(file1);
        UTILS_DIE_IF(file1_ptr->fail(), "Failed to open input_file!");
        s1 = file1_ptr.get();
    }

    if (file2.substr(0, 2) != "-.") {
        file2_ptr = genie::util::make_unique<std::ifstream>(file2);
        UTILS_DIE_IF(file2_ptr->fail(), "Failed to open sup_file!");
    } else {
        UTILS_DIE("Cannot use stdout as sup_file!");
    }

    if (file3.substr(0, 2) != "-.") {
        file3_ptr = genie::util::make_unique<std::ofstream>(file3, std::ofstream::binary | std::ofstream::app);
        UTILS_DIE_IF(file3_ptr->fail(), "Failed to open output_file!");
        o1 = file3_ptr.get();
    }

    flow->addImporter(genie::util::make_unique<genie::format::fastq::Importer>(BLOCKSIZE, *s1, *file2_ptr.get()));
    flow->addExporter(genie::util::make_unique<genie::format::mgrec::Exporter>(*o1));
    flow->run();

    if (file1_ptr) file1_ptr->close();
    if (file2_ptr) file2_ptr->close();
    if (file3_ptr) file3_ptr->close();
};

void convert_mgrec(rust::String input_file, rust::String output_file1, rust::String output_file2, size_t threads) {
    UTILS_DIE_IF(input_file.empty(), "input_file must be non-empty!");
    UTILS_DIE_IF(output_file1.empty(), "output_file1 must be non-empty!");

    std::string file1 = input_file.c_str();
    std::string file2 = output_file1.c_str();
    std::string file3 = output_file2.c_str();
    std::string tmp_file = file1 + ".unsupported.mgrec";
    std::unique_ptr<std::ifstream> file1_ptr;
    std::unique_ptr<std::ofstream> file2_ptr;
    std::unique_ptr<std::ofstream> file3_ptr;
    std::unique_ptr<std::ofstream> file4_ptr;
    std::istream* s1 = &std::cin;
    std::ostream* o1 = &std::cout;
    std::ostream* o2 = &std::cout;
    std::ostream* o3 = &std::cout;
    auto flow = genie::module::buildDefaultConverter(threads);

#ifdef DEBUG
    std::cout << "pwd: " << std::filesystem::current_path() << std::endl;
    std::cout << "input_file: " << file1 << std::endl;
    std::cout << "output_file: " << file2 << std::endl;
    std::cout << "output_file1: " << file3 << std::endl;
#endif

    if (file1.substr(0, 2) != ".-") {
        file1_ptr = genie::util::make_unique<std::ifstream>(file1, std::ifstream::binary);
        file4_ptr = genie::util::make_unique<std::ofstream>(tmp_file);
        UTILS_DIE_IF(file1_ptr->fail(), "Failed to open input_file!");
        UTILS_DIE_IF(file4_ptr->fail(), "Failed to open tmp_file!");
        s1 = file1_ptr.get();
        o3 = file4_ptr.get();
    }

    if (file2.substr(0, 2) != ".-") {
        file2_ptr = genie::util::make_unique<std::ofstream>(file2, std::ofstream::app);
        UTILS_DIE_IF(file2_ptr->fail(), "Failed to open output_file!");
        o1 = file2_ptr.get();
    }

    if (!file3.empty() && file3.substr(0, 2) != ".-") {
        file3_ptr = genie::util::make_unique<std::ofstream>(file3, std::ofstream::app);
        UTILS_DIE_IF(file3_ptr->fail(), "Failed to open output_file1!");
        o2 = file3_ptr.get();
    }

    flow->addImporter(genie::util::make_unique<genie::format::mgrec::Importer>(BLOCKSIZE, *s1, *o3, true));

    if (file_extension(file2) == "fastq") {
        if (file_extension(file3) == "fastq") {
            flow->addExporter(genie::util::make_unique<genie::format::fastq::Exporter>(*o1, *o2));
        } else {
            flow->addExporter(genie::util::make_unique<genie::format::fastq::Exporter>(*o1));
        }
    } else if (file_extension(file2) == "fasta") {
        flow->addExporter(genie::util::make_unique<genie::format::fasta::Exporter>(&flow->getRefMgr(), o1, threads));
    }

    flow->run();

    if (file1_ptr) file1_ptr->close();
    if (file2_ptr) file2_ptr->close();
    if (file3_ptr) file3_ptr->close();
    if (file4_ptr) file4_ptr->close();
}

}  // namespace geniesys