1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
//! A set of ValueFlows structs and utils auto-generated from the [RDF schema][1]. //! The structs are all serde-(de)serializable and are generically typed to //! allow a number of different methods of data modeling. //! //! The schema imports a number of structs from different RDF schemas, and each //! of them is namespaced in this crate, with the main classes generated living //! under `vf::*`. //! //! Given the nature of this library, it's important that various use cases are //! possible. For instance, you might want to model a VF system with all types //! tightly linked to each other as structs. You might want to loosely link the //! objects together with IDs (such as when storing in a normalized database). //! This means that the VF structs exported have generics for their identity //! field (`id`) as well as for any references to other VF objects. This allows //! using whatever types are desired when building out your desired system. //! //! The structs exported have builder structs defined for them using the //! wonderful [derive_builder][2] crate. So `Agent` also has a corresponding //! `AgentBuilder` struct. Builder structs use the "owned" pattern, meaning the //! builder methods consume the builder and return a new instance on each call. //! The best way to create builders is by using the built-in `builder()` //! function for each type (ie, `Agent::builder()`). Also, //! given an existing `Agent` struct instance, you can call //! `myaction.into_builder()` to convert (consume) it into an `AgentBuilder`, //! which makes immutable updates fairly easy. The builder methods implement //! Into so any type that has Into implemented for the field type can be //! passed. Note that builder methods also strip Option, so if a struct field //! is an Option<T> you can just pass T to the builder method. //! //! This library defines getters and setters for the provided structs via the //! [getset][3] crate. It's important to note that by default, only getters are //! defined. If you want setters, you can compiled with the feature //! `getset_setters` and if you want mutable getters, use `getset_getmut`. This //! allows side-stepping some of the enforced functional nature of the library //! if you find that sort of thing obnoxious. //! //! Features: //! //! - `into_builder` - (default) implements `.into_builder()` for provided //! structs so existing structs can be modified via the builder pattern. //! - `getset_setters` - implements setters on the generated structs so they can //! be mutated in-place via setter methods //! - `getset_getmut` - implements mutable getters on the generated structs so //! they can be mutated in-place via &mut getters //! //! Note that *all* features are enabled when building the docs to give a sense //! of the library's full abilities. //! //! ```rust //! use vf_rs::vf; //! //! // build a new action with the builder pattern, using String for the id field type //! let agent: vf::Agent = vf::Agent::builder() //! .name("Andrew") //! .note("His hands are big") //! .build().unwrap(); //! assert_eq!(agent.name(), "Andrew"); //! assert_eq!(agent.note(), &Some("His hands are big".to_string())); //! assert_eq!(agent.image(), &None); //! // create a new action with a different label //! let new_agent = agent.into_builder() //! .note("DOES NOT HAVE SMALL HANDS".to_string()) //! .build().unwrap(); //! assert_eq!(new_agent.name(), "Andrew"); //! assert_eq!(new_agent.note(), &Some("DOES NOT HAVE SMALL HANDS".to_string())); //! ``` //! //! [1]: https://github.com/valueflows/valueflows/blob/master/release-doc-in-process/all_vf.TTL //! [2]: https://colin-kiegel.github.io/rust-derive-builder/ //! [3]: https://docs.rs/getset/ mod gen; // import everything lol pub use gen::*; #[cfg(test)] mod test { use super::*; use serde_json; use url::Url; use chrono::prelude::*; #[test] fn builder() { let agent: vf::Agent = vf::Agent::builder() .name("Andrew") .note("His hands are big") .build().unwrap(); assert_eq!(agent.name(), "Andrew"); assert_eq!(agent.note(), &Some("His hands are big".to_string())); assert_eq!(agent.image(), &None); } #[cfg(feature = "into_builder")] #[test] fn into_builder() { let agent: vf::Agent = vf::Agent::builder() .name("Andrew") .note("His hands are big") .build().unwrap(); let agent_builder = agent.clone().into_builder(); let agent2 = agent_builder.build().unwrap(); assert_eq!(agent, agent2); let agent3 = agent.clone().into_builder() .name("LARRY".to_string()) .build().unwrap(); assert!(agent2 != agent3); } #[test] fn builder_throws_on_incomplete_struct() { let res: Result<vf::EconomicResource<String, String, String, String>, String> = vf::EconomicResource::builder() .name("hi my name is butch") .build(); match res { Ok(_) => panic!("Builder did not throw on missing required field"), Err(_) => {} } } #[test] fn builder_setter_into() { let agent: vf::Agent = vf::Agent::builder() .name("Andrew".to_string()) .build().unwrap(); assert_eq!(agent.name(), "Andrew"); let agent: vf::Agent = vf::Agent::builder() .name("Andrew") .build().unwrap(); assert_eq!(agent.name(), "Andrew"); } #[test] fn serializes() { let location = geo::SpatialThing::builder() .name("https://basisproject.gitlab.io/public/") .build().unwrap(); let agent: vf::Agent = vf::Agent::builder() .image("https://basisproject.gitlab.io/public/assets/images/red_star.256.outline.png".parse::<Url>().unwrap()) .name("Basis") .primary_location(location) .build().unwrap(); let json = serde_json::to_string(&agent).unwrap(); assert_eq!(json, r#"{"image":"https://basisproject.gitlab.io/public/assets/images/red_star.256.outline.png","name":"Basis","primary_location":{"name":"https://basisproject.gitlab.io/public/"}}"#); } #[test] fn deserializes() { let json = r#"{"image":"https://basisproject.gitlab.io/public/assets/images/red_star.256.outline.png","name":"Basis","primary_location":{"name":"https://basisproject.gitlab.io/public/"}}"#; let agent: vf::Agent = serde_json::from_str(json).unwrap(); let location = agent.primary_location().as_ref().unwrap(); assert_eq!(agent.image(), &Some("https://basisproject.gitlab.io/public/assets/images/red_star.256.outline.png".parse::<Url>().unwrap())); assert_eq!(agent.name(), "Basis"); assert_eq!(agent.note(), &None); assert_eq!(location.name(), &Some("https://basisproject.gitlab.io/public/".into())); } #[cfg(feature = "getset_setters")] #[test] fn getset_setters() { let mut plan = vf::Plan::builder() .created("2018-04-01T00:01:01Z".parse::<DateTime<Utc>>().unwrap()) .name("GOSHPLAN".to_string()) .build().unwrap(); assert_eq!(plan.name(), &Some("GOSHPLAN".to_string())); plan.set_name(Some("Gffft".into())); assert_eq!(plan.name(), &Some("Gffft".to_string())); } #[cfg(feature = "getset_getmut")] #[test] fn getset_getmut() { let mut plan = vf::Plan::builder() .created("2018-04-01T00:01:01Z".parse::<DateTime<Utc>>().unwrap()) .name("GOSHPLAN".to_string()) .build().unwrap(); assert_eq!(plan.name(), &Some("GOSHPLAN".to_string())); (*plan.name_mut()) = Some("Gffft".into()); assert_eq!(plan.name(), &Some("Gffft".to_string())); } /* #[test] fn buy_sell_flow() { let sandra = vf::Agent::builder() .name("Sandra") .build().unwrap(); let larry = vf::Agent::builder() .name("Larry") .build().unwrap(); let unit = om2::Unit::builder().label("one").symbol("o").build().unwrap(); let measure_one = om2::Measure::builder() .has_unit(unit.clone()) .has_numerical_value(dtype::NumericUnion::Integer(2)) .build().unwrap(); let plywood_spec = vf::ResourceSpecification::builder() .name("plywood") .resource_classified_as(vec!["https://www.wikidata.org/wiki/Q219803".parse().unwrap()]) .build().unwrap(); let sandras_plywood = vf::EconomicResource::builder() .accounting_quantity(measure_one.clone()) .classified_as(vec!["https://www.wikidata.org/wiki/Q219803".parse().unwrap()]) .conforms_to(plywood_spec.clone()) .note("Plywood sheet 1x1mx3cm") .build().unwrap(); let build_process = vf::Process::builder() .name("build the table") .classified_as(vec!["https://www.wikidata.org/wiki/Q219804".parse().unwrap()]) .build().unwrap(); let consume_event = vf::EconomicEvent::builder() .action(vf::Action::Consume) .input_of(build_process.clone()) .provider(sandra.clone()) .receiver(sandra.clone()) .build().unwrap(); let produce_event = vf::EconomicEvent::builder() .action(vf::Action::Produce) .input_of(build_process.clone()) .build().unwrap(); let table_spec = vf::ResourceSpecification::builder() .name("table") .resource_classified_as(vec!["https://www.wikidata.org/wiki/Q14748".parse().unwrap()]) .build().unwrap(); let table = vf::EconomicResource::builder() .accounting_quantity(measure_one.clone()) .classified_as(vec!["https://www.wikidata.org/wiki/Q14748".parse().unwrap()]) .conforms_to(plywood_spec.clone()) .note("Plywood table with no legs") .build().unwrap(); } */ }