diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f1feeaa --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.15...3.27) +project(can_ada) +find_package(Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED) + +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +execute_process( + COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR) +list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}") +find_package(nanobind CONFIG REQUIRED) + +nanobind_add_module(can_ada src/binding.cpp src/ada.cpp) \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c91373b --- /dev/null +++ b/LICENSE @@ -0,0 +1,43 @@ +-------------------------------------------------------------------------------- +The can_ada binding is available under the following licenses: + +Copyright 2024 Tyler Kennedy + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- +The included Ada project is used under the following license: + +Copyright 2023 Yagiz Nizipli and Daniel Lemire + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/setup.py b/setup.py index 9cb3788..c1808f9 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup from pybind11.setup_helpers import Pybind11Extension -__version__ = "1.1.1" +__version__ = "1.1.2" setup( name="can_ada", @@ -10,8 +10,9 @@ author_email="tk@tkte.ch", long_description_content_type="text/markdown", long_description=open("README.md").read(), - url="https://github.com/tktech/can-ada", + url="https://github.com/tktech/can_ada", description="Ada is a fast spec-compliant url parser", + license="MIT", ext_modules=[ Pybind11Extension( "can_ada", diff --git a/src/binding.cpp b/src/binding.cpp index 38dc87f..384ed09 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1,9 +1,10 @@ -#include +#include +#include #include "ada.h" -namespace py = pybind11; +namespace py = nanobind; -PYBIND11_MODULE(can_ada, m) { +NB_MODULE(can_ada, m) { #ifdef VERSION_INFO m.attr("__version__") = Py_STRINGIFY(VERSION_INFO); #else @@ -13,21 +14,21 @@ PYBIND11_MODULE(can_ada, m) { m.def("can_parse", &ada::can_parse, py::arg("input"), - py::arg("base_input") = static_cast(nullptr)); + py::arg("base_input") = static_cast(nullptr)); py::class_(m, "URL") - .def_property("hash", &ada::url_aggregator::get_hash, &ada::url_aggregator::set_hash) - .def_property("host", &ada::url_aggregator::get_host, &ada::url_aggregator::set_host) - .def_property("hostname", &ada::url_aggregator::get_hostname, &ada::url_aggregator::set_hostname) - .def_property("href", &ada::url_aggregator::get_href, &ada::url_aggregator::set_href) - .def_property("origin", &ada::url_aggregator::get_origin, nullptr) - .def_property("password", &ada::url_aggregator::get_password, &ada::url_aggregator::set_password) - .def_property("pathname", &ada::url_aggregator::get_pathname, &ada::url_aggregator::set_pathname) - .def_property("pathname_length", &ada::url_aggregator::get_pathname_length, nullptr) - .def_property("port", &ada::url_aggregator::get_port, &ada::url_aggregator::set_port) - .def_property("protocol", &ada::url_aggregator::get_protocol, &ada::url_aggregator::set_protocol) - .def_property("search", &ada::url_aggregator::get_search, &ada::url_aggregator::set_search) - .def_property("username", &ada::url_aggregator::get_username, &ada::url_aggregator::set_username) + .def_prop_rw("hash", &ada::url_aggregator::get_hash, &ada::url_aggregator::set_hash) + .def_prop_rw("host", &ada::url_aggregator::get_host, &ada::url_aggregator::set_host) + .def_prop_rw("hostname", &ada::url_aggregator::get_hostname, &ada::url_aggregator::set_hostname) + .def_prop_rw("href", &ada::url_aggregator::get_href, &ada::url_aggregator::set_href) + .def_prop_ro("origin", &ada::url_aggregator::get_origin) + .def_prop_rw("password", &ada::url_aggregator::get_password, &ada::url_aggregator::set_password) + .def_prop_rw("pathname", &ada::url_aggregator::get_pathname, &ada::url_aggregator::set_pathname) + .def_prop_ro("pathname_length", &ada::url_aggregator::get_pathname_length) + .def_prop_rw("port", &ada::url_aggregator::get_port, &ada::url_aggregator::set_port) + .def_prop_rw("protocol", &ada::url_aggregator::get_protocol, &ada::url_aggregator::set_protocol) + .def_prop_rw("search", &ada::url_aggregator::get_search, &ada::url_aggregator::set_search) + .def_prop_rw("username", &ada::url_aggregator::get_username, &ada::url_aggregator::set_username) .def("has_credentials", &ada::url_aggregator::has_credentials) .def("has_empty_hostname", &ada::url_aggregator::has_empty_hostname) @@ -44,15 +45,20 @@ PYBIND11_MODULE(can_ada, m) { .def("__str__", &ada::url_aggregator::get_href) .def("validate", &ada::url_aggregator::validate); - m.def("idna_decode", &ada::idna::to_unicode); - m.def("idna_encode", [](std::string input) -> py::bytes { - return py::bytes(ada::idna::to_ascii(input)); + m.def("idna_decode", [](py::bytes input) -> py::str { + auto result = ada::idna::to_unicode(input.c_str()); + return py::str(result.c_str()); }); - m.def("parse", [](std::string_view input) { + m.def("idna_encode", [](const std::string_view input) -> py::bytes { + auto result = ada::idna::to_ascii(input); + return py::bytes(result.c_str(), result.size()); + }); + + m.def("parse", [](const std::string_view input) { ada::result url = ada::parse(input); if (!url) { - throw pybind11::value_error("URL could not be parsed."); + throw py::value_error("URL could not be parsed."); } return url.value(); });