diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..874a0087 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.dm] +indent_style = tab diff --git a/Cargo.lock b/Cargo.lock index e902723f..36da917d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,9 +199,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "const-random" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dc82c12dc2ee6e1ded861cf7d582b46f66f796d1b6c93fa28b911ead95da02" +checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" dependencies = [ "const-random-macro", "proc-macro-hack", @@ -209,12 +209,14 @@ dependencies = [ [[package]] name = "const-random-macro" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc757bbb9544aa296c2ae00c679e81f886b37e28e59097defe0cf524306f6685" +checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" dependencies = [ "getrandom 0.2.0", + "lazy_static", "proc-macro-hack", + "tiny-keccak", ] [[package]] @@ -301,6 +303,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "dashmap" version = "3.11.10" @@ -314,9 +322,9 @@ dependencies = [ [[package]] name = "deflate" -version = "0.7.20" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" dependencies = [ "adler32", "byteorder", @@ -780,6 +788,24 @@ dependencies = [ "tiff", ] +[[package]] +name = "image" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985fc06b1304d19c28d5c562ed78ef5316183f2b0053b46763a0b94862373c34" +dependencies = [ + "bytemuck", + "byteorder", + "gif 0.11.1", + "jpeg-decoder", + "num-iter", + "num-rational 0.3.0", + "num-traits 0.2.12", + "png 0.16.7", + "scoped_threadpool", + "tiff", +] + [[package]] name = "indexmap" version = "1.6.0" @@ -1582,9 +1608,10 @@ dependencies = [ [[package]] name = "rust-g" -version = "0.4.6" +version = "0.4.7" dependencies = [ "chrono", + "const-random", "dashmap", "flume", "git2", @@ -1597,12 +1624,14 @@ dependencies = [ "once_cell", "percent-encoding", "png 0.16.7", + "rand 0.7.3", "reqwest", "serde", "serde_json", "sha-1", "sha2 0.9.1", "thiserror", + "twox-hash", "url", "zip", ] @@ -2013,6 +2042,15 @@ dependencies = [ "syn", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "0.3.4" @@ -2098,11 +2136,13 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "twox-hash" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" +checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" dependencies = [ + "cfg-if", "rand 0.7.3", + "static_assertions", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7a784d8d..07ecbc7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rust-g" edition = "2018" -version = "0.4.6" +version = "0.4.7" authors = ["Bjorn Neergaard "] repository = "https://github.com/tgstation/rust-g" license-file = "LICENSE" @@ -20,6 +20,8 @@ thiserror = "1.0" flume = { version = "0.9", optional = true } chrono = { version = "0.4", optional = true } md-5 = { version = "0.9", optional = true } +twox-hash = { version = "1.6.0", optional = true } +const-random = { version = "0.1.13", optional = true } sha-1 = { version = "0.9", optional = true } sha2 = { version = "0.9", optional = true } hex = { version = "0.4", optional = true } @@ -37,18 +39,26 @@ once_cell = { version = "1.4", optional = true } mysql = { version = "20.0", optional = true } dashmap = { version = "3.11", optional = true } zip = { version = "0.5.8", optional = true } +rand = {version = "0.7", optional = true} [features] -default = ["dmi", "log", "git", "http", "json", "sql", "noise"] +default = ["cellularnoise", "dmi", "file", "git", "http", "json", "log", "noise", "sql"] + +# default features +cellularnoise = ["rand"] dmi = ["png", "image"] file = [] -hash = ["md-5", "sha-1", "sha2", "hex"] -json = ["serde", "serde_json"] -log = ["chrono"] -url = ["url-dep", "percent-encoding"] git = ["git2", "chrono"] http = ["reqwest", "serde", "serde_json", "once_cell", "jobs"] +json = ["serde", "serde_json"] +log = ["chrono"] sql = ["mysql", "serde", "serde_json", "once_cell", "dashmap", "jobs"] -jobs = ["flume"] + +# non-default features +hash = ["md-5", "sha-1", "sha2", "hex", "twox-hash", "const-random"] +url = ["url-dep", "percent-encoding"] unzip = ["zip", "jobs"] + +# internal feature-like things +jobs = ["flume"] diff --git a/README.md b/README.md index fe4ba3f9..39ab9c41 100644 --- a/README.md +++ b/README.md @@ -52,49 +52,46 @@ System libraries: sudo apt-get install zlib1g-dev:i386 libssl-dev:i386 pkg-config:i386 ``` -* Other distributions install the appropriate **32-bit development** and **32-bit runtime** packages. +* Other Linux distributions install the appropriate **32-bit development** and **32-bit runtime** packages. ## Compiling -The [cargo] tool handles compilation, as well as automatically downloading and +The [Cargo] tool handles compilation, as well as automatically downloading and compiling all Rust dependencies. The default configuration is suitable for use with the [tgstation] codebase, but not [beestation]. To compile in release mode: +Linux: ```sh -# Linux -cargo build --release --target=i686-unknown-linux-gnu -# Windows -cargo build --release --target=i686-pc-windows-msvc +export PKG_CONFIG_ALLOW_CROSS=1 +cargo build --release --target i686-unknown-linux-gnu +# output: target/i686-unknown-linux-gnu/release/librust_g.so ``` -On Linux, the output will be `target/release/librust_g.so`. - -On Windows, the output will be `target/release/rust_g.dll`. - -For more advanced configuration, a list of modules may be passed: +Windows: ```sh -export PKG_CONFIG_ALLOW_CROSS=1 -# Linux -cargo build --release --target=i686-unknown-linux-gnu --features dmi,file,log,url,http,noise,json -# Windows -cargo build --release --target=i686-pc-windows-msvc --features dmi,file,log,url,http,noise,json +cargo build --release --target i686-pc-windows-msvc +# output: target/i686-pc-windows-msvc/release/rust_g.dll ``` +To get additional features, pass a list to `--features`, for example `--features hash,url`. To get all features, pass `--all-features`. To disable the default features, pass `--no-default-features`. + The default features are: -* log: Faster log output. +* cellularnoise: Function to generate cellular automata-based noise. * dmi: DMI manipulations which are impossible from within BYOND. Used by the asset cache subsystem to improve load times. +* file: Faster replacements for `file2text` and `text2file`, as well as reading or checking if files exist. * git: Functions for robustly checking the current git revision. * http: Asynchronous HTTP(s) client supporting most standard methods. +* json: Function to check JSON validity. +* log: Faster log output. * sql: Asynchronous MySQL/MariaDB client library. * noise: 2d Perlin noise. -* json: Function to check JSON validity. Additional features are: -* url: Faster replacements for `url_encode` and `url_decode`. -* file: Faster replacements for `file2text` and `text2file`, as well as reading or checking if files exist. * hash: Faster replacement for `md5`, support for SHA-1, SHA-256, and SHA-512. Requires OpenSSL on Linux. +* url: Faster replacements for `url_encode` and `url_decode`. +* unzip: Function to download a .zip from a URL and unzip it to a directory. ## Installing @@ -112,7 +109,6 @@ at the top of `rust_g.dm` for details. You must build a 32-bit version of the library for it to be compatible with BYOND. Attempting to build a 64-bit version will fail with an explanatory error. -Use the `rustup override add` command described above or build with `--target`. ### Linux @@ -169,9 +165,9 @@ If you're still having problems, ask in the [Coderbus Discord]'s `#tooling-questions` channel. [tgstation]: https://github.com/tgstation/tgstation -[ beestation ]: https://github.com/beestation/beestation-hornet +[beestation]: https://github.com/beestation/beestation-hornet [Rust]: https://rust-lang.org -[cargo]: https://doc.rust-lang.org/cargo/ +[Cargo]: https://doc.rust-lang.org/cargo/ [rustup]: https://rustup.rs/ [msvc]: https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15 [Coderbus Discord]: https://discord.gg/Vh8TJp9 diff --git a/dmsrc/cellularnoise.dm b/dmsrc/cellularnoise.dm new file mode 100644 index 00000000..2f48dd9d --- /dev/null +++ b/dmsrc/cellularnoise.dm @@ -0,0 +1,15 @@ +/** + * This proc generates a cellular automata noise grid which can be used in procedural generation methods. + * + * Returns a single string that goes row by row, with values of 1 representing an alive cell, and a value of 0 representing a dead cell. + * + * Arguments: + * * percentage: The chance of a turf starting closed + * * smoothing_iterations: The amount of iterations the cellular automata simulates before returning the results + * * birth_limit: If the number of neighboring cells is higher than this amount, a cell is born + * * death_limit: If the number of neighboring cells is lower than this amount, a cell dies + * * width: The width of the grid. + * * height: The height of the grid. + */ +#define rustg_cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) \ + call(RUST_G, "cnoise_generate")(percentage, smoothing_iterations, birth_limit, death_limit, width, height) diff --git a/dmsrc/dmi.dm b/dmsrc/dmi.dm index d0fb81b8..b9baca82 100644 --- a/dmsrc/dmi.dm +++ b/dmsrc/dmi.dm @@ -1,3 +1,3 @@ -#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) -#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data) -#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype) \ No newline at end of file +#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) +#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data) +#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype) diff --git a/dmsrc/file.dm b/dmsrc/file.dm index 2428eb86..e0c30336 100644 --- a/dmsrc/file.dm +++ b/dmsrc/file.dm @@ -4,6 +4,6 @@ #define rustg_file_append(text, fname) call(RUST_G, "file_append")(text, fname) #ifdef RUSTG_OVERRIDE_BUILTINS - #define file2text(fname) rustg_file_read("[fname]") - #define text2file(text, fname) rustg_file_append(text, "[fname]") -#endif \ No newline at end of file + #define file2text(fname) rustg_file_read("[fname]") + #define text2file(text, fname) rustg_file_append(text, "[fname]") +#endif diff --git a/dmsrc/git.dm b/dmsrc/git.dm index 0ae30188..b121e7f0 100644 --- a/dmsrc/git.dm +++ b/dmsrc/git.dm @@ -1,2 +1,2 @@ -#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev) -#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev) \ No newline at end of file +#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev) +#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev) diff --git a/dmsrc/hash.dm b/dmsrc/hash.dm index 8087654a..3ecedc6f 100644 --- a/dmsrc/hash.dm +++ b/dmsrc/hash.dm @@ -5,7 +5,8 @@ #define RUSTG_HASH_SHA1 "sha1" #define RUSTG_HASH_SHA256 "sha256" #define RUSTG_HASH_SHA512 "sha512" +#define RUSTG_HASH_XXH64 "xxh64" #ifdef RUSTG_OVERRIDE_BUILTINS -#define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing)) -#endif \ No newline at end of file + #define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing)) +#endif diff --git a/dmsrc/http.dm b/dmsrc/http.dm index 6f8aa88a..93d964bb 100644 --- a/dmsrc/http.dm +++ b/dmsrc/http.dm @@ -4,6 +4,6 @@ #define RUSTG_HTTP_METHOD_PATCH "patch" #define RUSTG_HTTP_METHOD_HEAD "head" #define RUSTG_HTTP_METHOD_POST "post" -#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers) -#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers) -#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id) \ No newline at end of file +#define rustg_http_request_blocking(method, url, body, headers, options) call(RUST_G, "http_request_blocking")(method, url, body, headers, options) +#define rustg_http_request_async(method, url, body, headers, options) call(RUST_G, "http_request_async")(method, url, body, headers, options) +#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id) diff --git a/dmsrc/jobs.dm b/dmsrc/jobs.dm index 6ca2c0bc..e882ddb7 100644 --- a/dmsrc/jobs.dm +++ b/dmsrc/jobs.dm @@ -1,3 +1,3 @@ -#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" -#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" -#define RUSTG_JOB_ERROR "JOB PANICKED" \ No newline at end of file +#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" +#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB" +#define RUSTG_JOB_ERROR "JOB PANICKED" diff --git a/dmsrc/json.dm b/dmsrc/json.dm index d3e06ce6..80a18539 100644 --- a/dmsrc/json.dm +++ b/dmsrc/json.dm @@ -1 +1 @@ -#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true") \ No newline at end of file +#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true") diff --git a/dmsrc/log.dm b/dmsrc/log.dm index 5e2371cb..709b484e 100644 --- a/dmsrc/log.dm +++ b/dmsrc/log.dm @@ -1,2 +1,2 @@ -#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format) -/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() \ No newline at end of file +#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format) +/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() diff --git a/dmsrc/main.dm b/dmsrc/main.dm index 3dd4db9c..80099ca0 100644 --- a/dmsrc/main.dm +++ b/dmsrc/main.dm @@ -36,4 +36,4 @@ return __rust_g = "rust_g" #define RUST_G (__rust_g || __detect_rust_g()) -#endif \ No newline at end of file +#endif diff --git a/dmsrc/noise.dm b/dmsrc/noise.dm index 04533365..6277a462 100644 --- a/dmsrc/noise.dm +++ b/dmsrc/noise.dm @@ -1 +1 @@ -#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y) \ No newline at end of file +#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y) diff --git a/dmsrc/sql.dm b/dmsrc/sql.dm index 5c8b0978..d3bfc49b 100644 --- a/dmsrc/sql.dm +++ b/dmsrc/sql.dm @@ -3,4 +3,4 @@ #define rustg_sql_query_blocking(handle, query, params) call(RUST_G, "sql_query_blocking")(handle, query, params) #define rustg_sql_connected(handle) call(RUST_G, "sql_connected")(handle) #define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle) -#define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]") \ No newline at end of file +#define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]") diff --git a/dmsrc/unzip.dm b/dmsrc/unzip.dm index be56e5f3..ce945b1b 100644 --- a/dmsrc/unzip.dm +++ b/dmsrc/unzip.dm @@ -1,2 +1,2 @@ #define rustg_unzip_download_async(url, unzip_directory) call(RUST_G, "unzip_download_async")(url, unzip_directory) -#define rustg_unzip_check(job_id) call(RUST_G, "unzip_check")("[job_id]") \ No newline at end of file +#define rustg_unzip_check(job_id) call(RUST_G, "unzip_check")("[job_id]") diff --git a/dmsrc/url.dm b/dmsrc/url.dm index 1fd2cce5..914b8bb9 100644 --- a/dmsrc/url.dm +++ b/dmsrc/url.dm @@ -2,6 +2,6 @@ #define rustg_url_decode(text) call(RUST_G, "url_decode")(text) #ifdef RUSTG_OVERRIDE_BUILTINS - #define url_encode(text) rustg_url_encode(text) - #define url_decode(text) rustg_url_decode(text) -#endif \ No newline at end of file + #define url_encode(text) rustg_url_encode(text) + #define url_decode(text) rustg_url_decode(text) +#endif diff --git a/src/byond.rs b/src/byond.rs index 379386b8..68925ce3 100644 --- a/src/byond.rs +++ b/src/byond.rs @@ -56,10 +56,10 @@ macro_rules! byond_fn { ($name:ident($($arg:ident),* $(, ...$rest:ident)?) $body:block) => { #[no_mangle] #[allow(clippy::missing_safety_doc)] - pub unsafe extern "C" fn $name( + pub extern "C" fn $name( _argc: ::std::os::raw::c_int, _argv: *const *const ::std::os::raw::c_char ) -> *const ::std::os::raw::c_char { - let __args = $crate::byond::parse_args(_argc, _argv); + let __args = unsafe { $crate::byond::parse_args(_argc, _argv) }; let mut __argn = 0; $( diff --git a/src/cellularnoise.rs b/src/cellularnoise.rs new file mode 100644 index 00000000..3c837e27 --- /dev/null +++ b/src/cellularnoise.rs @@ -0,0 +1,100 @@ +use crate::error::Result; +use rand::*; +use std::fmt::Write; + +byond_fn! { cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) { + noise_gen(percentage, smoothing_iterations, birth_limit, death_limit, width, height).ok() +} } + +fn noise_gen( + percentage_as_str: &str, + smoothing_level_as_str: &str, + birth_limit_as_str: &str, + death_limit_as_str: &str, + width_as_str: &str, + height_as_str: &str, +) -> Result { + let percentage = percentage_as_str.parse::()?; + let smoothing_level = smoothing_level_as_str.parse::()?; + let birth_limit = birth_limit_as_str.parse::()?; + let death_limit = death_limit_as_str.parse::()?; + let width = width_as_str.parse::()?; + let height = height_as_str.parse::()?; + + // Noise generation + let mut zplane = vec![vec![false; width]; height]; + for row in zplane.iter_mut() { + for cell in row.iter_mut() { + *cell = rand::thread_rng().gen_range(0, 100) < percentage; + } + } + + // Smoothing part + for _timer in 0..smoothing_level { + let zplane_old = zplane.clone(); + for i in 0..height { + for j in 0..width { + let mut sum = 0; + + if i > 0 { + if j > 0 { + sum += if zplane_old[i - 1][j - 1] { 1 } else { 0 }; + } + + sum += if zplane_old[i - 1][j] { 1 } else { 0 }; + + if j + 1 < width { + sum += if zplane_old[i - 1][j + 1] { 1 } else { 0 }; + } + } + + if j > 0 { + sum += if zplane_old[i][j - 1] { 1 } else { 0 }; + } + + if j + 1 < width { + sum += if zplane_old[i][j + 1] { 1 } else { 0 }; + } + + if i + 1 < height { + if j > 0 { + sum += if zplane_old[i + 1][j - 1] { 1 } else { 0 }; + } + + sum += if zplane_old[i + 1][j] { 1 } else { 0 }; + + if j + 1 < width { + sum += if zplane_old[i + 1][j + 1] { 1 } else { 0 }; + } + } + + if zplane_old[i][j] == true { + if sum < death_limit { + zplane[i][j] = false; + } else { + zplane[i][j] = true; + } + } else { + if sum > birth_limit { + zplane[i][j] = true; + } else { + zplane[i][j] = false; + } + } + } + } + } + + let mut string = String::new(); + for row in zplane.iter() { + for cell in row.iter() { + if *cell { + let _ = write!(string, "1"); + } else { + let _ = write!(string, "0"); + } + } + } + + Ok(string) +} diff --git a/src/hash.rs b/src/hash.rs index 05e53098..15914912 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,12 +1,18 @@ use crate::error::{Error, Result}; +use const_random::const_random ; +const XXHASH_SEED: u64 = const_random!(u64); +use twox_hash::XxHash64; use md5::Md5; use sha1::Sha1; use sha2::{Digest, Sha256, Sha512}; use std::{ fs::File, io::{BufReader, Read}, + hash::Hasher, }; + + byond_fn! { hash_string(algorithm, string) { string_hash(algorithm, string).ok() } } @@ -37,6 +43,11 @@ fn hash_algorithm>(name: &str, bytes: B) -> Result { hasher.update(bytes.as_ref()); Ok(hex::encode(hasher.finalize())) } + "xxh64" => { + let mut hasher = XxHash64::with_seed(XXHASH_SEED); + hasher.write(bytes.as_ref()); + Ok(format!("{:x}",hasher.finish())) + } _ => Err(Error::InvalidAlgorithm), } } diff --git a/src/lib.rs b/src/lib.rs index b843fb54..b2c779ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,8 @@ pub mod sql; pub mod url; #[cfg(feature = "unzip")] pub mod unzip; +#[cfg(feature = "cellularnoise")] +pub mod cellularnoise; #[cfg(not(target_pointer_width = "32"))] compile_error!("rust-g must be compiled for a 32-bit target");