{"id":18113858,"url":"https://github.com/jezza/def_mod","last_synced_at":"2025-07-17T09:35:43.824Z","repository":{"id":57617312,"uuid":"162361780","full_name":"Jezza/def_mod","owner":"Jezza","description":"A proc macro that simplifies implementation routing and statically verifies module exports.","archived":false,"fork":false,"pushed_at":"2019-07-31T21:20:47.000Z","size":17,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T02:47:58.311Z","etag":null,"topics":["compile-time","implementation-routing","macros","modules","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jezza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-19T00:38:07.000Z","updated_at":"2019-10-11T17:02:03.000Z","dependencies_parsed_at":"2022-08-29T05:40:18.990Z","dependency_job_id":null,"html_url":"https://github.com/Jezza/def_mod","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jezza%2Fdef_mod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jezza%2Fdef_mod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jezza%2Fdef_mod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jezza%2Fdef_mod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jezza","download_url":"https://codeload.github.com/Jezza/def_mod/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457809,"owners_count":20941906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compile-time","implementation-routing","macros","modules","rust"],"created_at":"2024-11-01T02:10:08.420Z","updated_at":"2025-04-06T09:14:12.347Z","avatar_url":"https://github.com/Jezza.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"`def_mod!` provides a familiar syntax to the standard module declarations, but with the added benefit\nof simpler implementation routing and statically verified module exports.\n\n---\n```rust\nextern crate def_mod;\n\nuse def_mod::def_mod;\n\ndef_mod! {\n\t// This has the exact same behaviour as Rust's.\n\tmod my_mod;\n\n\t// Much like the one above, it also has the same effect as Rust's.\n\tmod my_first_mod {\n\t\t// This will check if a method with the name `method` and type `fn(u32) -\u003e u8` was exported.\n    \t// It will fail to compile if it finds none.\n\t\tfn method(_: u32) -\u003e u8;\n\n\t\t// Much like the method declaration from above, this will check to see if a type was exported.\n\t\ttype MyStruct;\n\n\t\t// Much like the normal method check, that functionality is also extended to types.\n\t\t// So you can check if a type has a specific method exported.\n\t\ttype MyOtherStruct {\n\t\t\t// This will check if this method exists on this type. (MyOtherStruct::method)\n\t\t\tfn method(_: u32) -\u003e u8;\n\t\t}\n\t}\n\n\t// You can declare attributes like normal.\n\t#[cfg(windows)]\n\tmod my_second_mod;\n\n\t// When declaring an attribute, you can optionally add a string literal.\n\t// This literal is used as the path attribute for the module file.\n\t// All attributes declared with a path are treated as _mutually exclusive_.\n\t// So a `mod` declaration is generated for each.\n\t// This makes it a lot easier to manage cross-platform code.\n\t// Note: attributes that don't have a path are copied to each module declaration.\n\n\t#[cfg(windows)] = \"sys/win/mod.rs\"\n\t#[cfg(not(windows))] = \"sys/nix/mod.rs\"\n\tmod sys;\n\n\t// Expands to:\n\n\t#[cfg(windows)]\n\t#[path = \"sys/win/mod.rs\"]\n\tmod sys;\n\n\t#[cfg(not(windows))]\n\t#[path = \"sys/nix/mod.rs\"]\n\tmod sys;\n\n\t// You can also declare attributes on methods or types themselves, and they will be used when verifying the type.\n\t// This module itself will be verified when not on a windows system.\n\t#[cfg(not(windows))]\n\tmod my_third_mod {\n\t\t// This method will only be verified when on linux.\n\t\t#[cfg(linux)]\n\t\tfn interop() -\u003e u8;\n\t\t// Same with this type. It will only be verified when on a macos system\n\t\t#[cfg(macos)]\n\t\ttype SomeStruct {\n\t\t\tfn interop() -\u003e u8;\n\t\t}\n\t}\n}\n\nfn main() {\n}\n```\n\nNOTE: that `def_mod` uses syntax tricks to assert for types.  \nSo that means when you use the path shorthand, it will still only check the module that is loaded, not all potential modules.    \n\nOne good example is when you have two different modules for specific platforms.  \nThe module that would be compiled normally is the only one that would be checked.  \nYou would need to explicitly enable compilation of the modules if you want them to be checked too.  \nBecause you can declare arbitrary #[cfg] attributes, there's no generic way for `def_mod` to know how to do this.    \nIt's entirely up to you.  \n\n---\n\nIn case you're curious as to what the macro generates:\n\nA method assertion is transformed to something like:\n\n```rust\nfn method(_: u32) -\u003e u8;\n\n// into\n\nconst _VALUE: fn(u32) -\u003e u8 = my_mod::method;\n```\n\nA method assertion with generics is a bit more complex:\n\n```rust\nfn generic\u003c'a , T: 'a\u003e(_: u32, _: T, _: fn(T) -\u003e T) -\u003e \u0026'a T;\n\n// will turn into into (Note: This is nested inside of the load function itself.)\n\n#[allow(non_snake_case)]\nfn _load_module_name_generic\u003c'a, T: 'a\u003e() {\n\tlet _VALUE:\n\t\t\tfn(_: u32, _: T,\n\t\t\t   _: fn(T) -\u003e T) -\u003e \u0026'a T =\n\t\tother::generic;\n}\n```\n\nA type assertion is transformed into a new scope with a use declaration:\n\n```rust\ndef_mod! {\n\tmod my_mod {\n\t\ttype Test;\n\t}\n}\n\n// Into\n\n{\n\tuse self::my_mod::Test;\n\t// Any method assertions for the type will also be placed inside the same scope.\n}\n```\n\nAll of those are shoved into a function generated by the macro.\n\nFor example, given something like:\n\n```rust\ndef_mod! {\n\tmod my_mod {\n\t\tfn plus_one(value: u8) -\u003e u8;\n\n\t\ttype MyStruct {\n\t\t\tfn new() -\u003e Self;\n\t\t\tfn dupe(\u0026self) -\u003e Self;\n\t\t\tfn clear(\u0026mut self);\n\t\t}\n\n\t\tfn generic\u003c'a , T: 'a\u003e(_: u32, _: T, _: fn(T) -\u003e T) -\u003e \u0026'a T;\n\t}\n}\n```\n\nIt'll turn it into something like this:\n\n```rust\nmod my_mod;\n\nfn _load_my_mod() {\n\tconst _ASSERT_METHOD_0: fn(u8) -\u003e u8 = self::my_mod::plus_one;\n\t{\n\t\tuse self::my_mod::MyStruct;\n\t\tconst _ASSERT_METHOD_1: fn() -\u003e MyStruct = MyStruct::new;\n\t\tconst _ASSERT_METHOD_2: fn(_self: \u0026MyStruct) -\u003e MyStruct = MyStruct::dupe;\n\t\tconst _ASSERT_METHOD_3: fn(_self: \u0026mut MyStruct) -\u003e MyStruct = MyStruct::clear;\n\t}\n\t#[allow(non_snake_case)]\n    fn _load_my_mod_generic\u003c'a, T: 'a\u003e() {\n    \tlet _ASSERT_METHOD_4:\n    \t\t\tfn(_: u32, _: T,\n    \t\t\t   _: fn(T) -\u003e T) -\u003e \u0026'a T =\n    \t\tmy_mod::generic;\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjezza%2Fdef_mod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjezza%2Fdef_mod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjezza%2Fdef_mod/lists"}