From 75025fb79b8adea3ce7e4532f4db38e3df1ebf8f Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Sat, 14 Mar 2020 12:10:51 -0400 Subject: [PATCH] Add some more broken code. See scratch.rs for what does work. --- src/examples.rs | 104 +++++++++++++++++++++++++++++------------ src/lib.rs | 1 + src/rule.rs | 5 +- src/scratch.rs | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+), 30 deletions(-) create mode 100644 src/scratch.rs diff --git a/src/examples.rs b/src/examples.rs index 6b7ec1a..8e69a80 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,3 +1,4 @@ +use std::rc::Rc; use nalgebra::*; //pub mod examples; @@ -5,15 +6,12 @@ use crate::openmesh::{OpenMesh, Tag, Mat4, Vertex, vertex, transform}; use crate::rule::{Rule, RuleEval, Child}; use crate::prim; use crate::util; +use crate::scratch; -fn recurRule RuleEval>(f: A) -> Rule { - Rule { - eval: Box::new(f), - } -} - +/* +#[derive(Copy, Clone)] struct CurveHorn { - seed: Vec, + seed: [Vertex; 4], id_xform: Mat4, flip180: Mat4, incr: Mat4, @@ -21,10 +19,29 @@ struct CurveHorn { impl CurveHorn { + fn test_thing(&self) { + let f: Box RuleEval> = Box::new(move || self.do_nothing()); + println!("{:p}", f); + } + + fn do_nothing(&self) -> RuleEval { + RuleEval { + geom: prim::empty_mesh(), + final_geom: prim::empty_mesh(), + children: vec![ + Child { + rule: Rule { eval: Box::new(move || self.do_nothing()) }, + xf: self.id_xform, + vmap: vec![0,1,2,3], + }, + ], + } + } + fn init() -> Rule { let y = &Vector3::y_axis(); let c = CurveHorn { - seed: vec![ + seed: [ vertex(-0.5, -0.5, 0.0), vertex(-0.5, 0.5, 0.0), vertex( 0.5, 0.5, 0.0), @@ -38,24 +55,24 @@ impl CurveHorn { Matrix4::new_scaling(0.95) * geometry::Translation3::new(0.0, 0.0, 0.2).to_homogeneous(), }; - recurRule(|| c.start()) + Rule { eval: Box::new(move || c.do_nothing()) } } - +} fn start(&self) -> RuleEval { RuleEval { geom: OpenMesh { - verts: self.seed.clone(), + verts: self.seed.to_vec(), faces: vec![], }, final_geom: prim::empty_mesh(), children: vec![ Child { - rule: recurRule(|| self.recur()), + rule: Rule { eval: Box::new(move || self.recur()) }, xf: self.id_xform, vmap: vec![0,1,2,3], }, Child { - rule: recurRule(|| self.recur()), + rule: Rule { eval: Box::new(move || self.recur()) }, xf: self.flip180, vmap: vec![3,2,1,0], }, @@ -101,7 +118,7 @@ impl CurveHorn { final_geom: final_geom, children: vec![ Child { - rule: recurRule(|| self.recur()), + rule: Rule { eval: Box::new(move || self.recur()) }, xf: self.incr, vmap: vec![0,1,2,3], }, @@ -117,7 +134,7 @@ impl CubeThing { fn init() -> Rule { let c = CubeThing {}; - recurRule(|| c.rec()) + Rule { eval: Box::new(|| c.rec()) } } fn rec(&self) -> RuleEval { @@ -145,7 +162,7 @@ impl CubeThing { Matrix4::new_scaling(0.5) * geometry::Translation3::new(6.0, 0.0, 0.0).to_homogeneous(); Child { - rule: recurRule(|| self.rec()), + rule: Rule { eval: Box::new(|| self.rec()) }, xf: m, vmap: vec![], } @@ -166,7 +183,7 @@ impl RamHorn { fn init() -> Rule { let r = RamHorn{}; - recurRule(|| r.start()) + Rule { eval: Box::new(|| r.start()) } } // Conversion from Python & automata_scratch @@ -226,22 +243,22 @@ impl RamHorn { final_geom: prim::empty_mesh(), children: vec![ Child { - rule: recurRule(|| self.ram_horn()), + rule: Rule { eval: Box::new(|| self.ram_horn()) }, xf: opening_xform(0.0), vmap: vec![5,2,6,8], }, Child { - rule: recurRule(|| self.ram_horn()), + rule: Rule { eval: Box::new(|| self.ram_horn()) }, xf: opening_xform(1.0), vmap: vec![4,1,5,8], }, Child { - rule: recurRule(|| self.ram_horn()), + rule: Rule { eval: Box::new(|| self.ram_horn()) }, xf: opening_xform(2.0), vmap: vec![7,0,4,8], }, Child { - rule: recurRule(|| self.ram_horn()), + rule: Rule { eval: Box::new(|| self.ram_horn()) }, xf: opening_xform(3.0), vmap: vec![6,3,7,8], }, @@ -288,7 +305,7 @@ impl RamHorn { final_geom: final_geom, children: vec![ Child { - rule: recurRule(|| self.ram_horn()), + rule: Rule { eval: Box::new(|| self.ram_horn()) }, xf: incr, vmap: vec![0,1,2,3], }, @@ -327,7 +344,7 @@ impl Twist { seed_sub: seed_sub, subdiv: subdiv, }; - recurRule(|| t.start()) + Rule { eval: Box::new(|| t.start()) } } // Meant to be a copy of twist_from_gen from Python & automata_scratch @@ -348,7 +365,7 @@ impl Twist { let children: Vec = (0..self.count).map(|i| { let xf = xform(i); Child { - rule: recurRule(|| self.recur()), + rule: Rule { eval: Box::new(|| self.recur()) }, xf: xf, vmap: ((n+1)*i..(n+1)*(i+self.count)).collect(), // N.B. // note n+1, not n. the +1 is for the centroid below @@ -392,7 +409,7 @@ impl Twist { final_geom: OpenMesh { verts: vec![vc], faces }, children: vec![ Child { - rule: recurRule(|| self.recur()), + rule: Rule { eval: Box::new(move || self.recur()) }, xf: incr, vmap: (0..n).collect(), }, @@ -400,9 +417,11 @@ impl Twist { } } } +*/ pub fn main() { + /* { let vs = vec![ vertex(-0.5, 0.0, -0.5), @@ -432,6 +451,7 @@ pub fn main() { println!("Writing {}...", fname); mesh.write_stl_file(&fname).unwrap(); } + */ /* run_test(CubeThing::init(), Rule { eval: CubeThing::rec }, 3, "cube_thing"); @@ -443,15 +463,41 @@ pub fn main() { run_test(Twist::init(), Rule { eval: Twist::start }, 200, "twist"); */ - run_test_iter(CubeThing::init(), 3, "cube_thing2"); - run_test_iter(CurveHorn::init(), 100, "curve_horn2_iter"); - run_test_iter(RamHorn::init(), 100, "ram_horn2"); + //run_test_iter(CubeThing::init(), 3, "cube_thing2"); + //run_test_iter(CurveHorn::init(), 100, "curve_horn2_iter"); + //run_test_iter(RamHorn::init(), 100, "ram_horn2"); // TODO: If I increase the above from 100 to ~150, Blender reports // that the very tips are non-manifold. I am wondering if this is // some sort of numerical precision issue. - run_test_iter(Twist::init(1.0, 2), 100, "twist"); + //run_test_iter(Twist::init(1.0, 2), 100, "twist"); // This is a stress test: // let f = 20; // run_test_iter(Twist::init(f as f32, 32), 100*f, "twist2"); + + { + let a = vec![1,2,3]; + + let c = move || { + println!("c: a={:?}", a); + }; + + let r: Rc = Rc::new(c); + // But this will fail at the function calls below: + //let r: Rc = Rc::new(c); + let r2 = r.clone(); + + println!("strong_count={}", Rc::strong_count(&r2)); + println!("weak_count={}", Rc::weak_count(&r2)); + + r2(); + r(); + + let a2 = vec![1,2,3]; + let c2 = move || { + println!("c2: a2={:?}", a2); + }; + let b: Box = Box::new(c2); + b(); + } } diff --git a/src/lib.rs b/src/lib.rs index 32daf02..2308825 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod scratch; pub mod examples; pub mod openmesh; pub mod rule; diff --git a/src/rule.rs b/src/rule.rs index e814316..397961c 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -7,12 +7,15 @@ use crate::openmesh::{OpenMesh, Tag, Mat4}; /// - tells what other rules to invoke, and what to do with their /// geometry pub struct Rule { - pub eval: Box RuleEval>, + pub eval: Box RuleEval>, } // TODO: It may be possible to have just a 'static' rule that requires // no function call. // TODO: Do I benefit with Rc below so Rule can be shared? +// The above looks like it is going to require a lifetime parameter +// regardless, in which case I don't really need Box. + /// `RuleEval` supplies the results of evaluating some `Rule` for one /// iteration: it contains the geometry produced at this step /// (`geom`), and it tells what to do next depending on whether diff --git a/src/scratch.rs b/src/scratch.rs new file mode 100644 index 0000000..66c544e --- /dev/null +++ b/src/scratch.rs @@ -0,0 +1,120 @@ +use std::rc::Rc; + +/* +struct R<'a> { + b: &'a dyn Fn() -> R<'a>, +} + +#[derive(Copy, Clone)] +struct Foo {} +impl<'a> Foo { + // These are valid, but not especially useful (if I am + // transferring ownership then I cannot have any branching): + fn fn1(self) -> R<'a> { + R { b: & move || self.fn1() } + } + fn fn2(self) -> R<'a> { + R { b: &|| self.fn2() } + } +} +*/ + +// Below (using box instead of a trait object) follows similar rules: +struct S<'a> { + b: Box S<'a>>, +} +#[derive(Copy, Clone)] +struct Foo2 {} +impl<'a> Foo2 { + fn fn1(self) -> S<'a> { + S { b: Box::new(move || self.fn1()) } + } + // Not valid (error[E0373]: closure may outlive the current + // function, but it borrows `self`, which is owned by the current + // function): + //fn fn2(self) -> S<'a> { + // S { b: Box::new(|| self.fn2()) } + //} + // Not valid: + //fn fn3(&self) -> S<'a> { + // S { b: Box::new(move || self.fn3()) } + //} + // Not valid: + //fn fn4(&self) -> S<'a> { + // S { b: Box::new(|| self.fn4()) } + //} +} + +struct T<'a> { + b: Rc T<'a> + 'a>, +} +#[derive(Copy, Clone)] +struct Foo3 {} +impl<'a> Foo3 { + fn fn1(self) -> T<'a> { + T { b: Rc::new(move || self.fn1()) } + } + // Not valid (E0373): + //fn fn2(self) -> T<'a> { + // T { b: Rc::new(|| self.fn2()) } + //} + // Not valid: + //fn fn3(&self) -> T<'a> { + // T { b: Rc::new(move || self.fn3()) } + //} + // Not valid: + //fn fn4(&self) -> T<'a> { + // T { b: Rc::new(|| self.fn4()) } + //} + // But this is now valid because T can be cloned: + fn fn5(self) -> (T<'a>, T<'a>) { + let p = Rc::new(move || self.fn1()); + let p2 = p.clone(); + (T { b: p }, T { b: p2 }) + } +} + +// Further, this is now valid too (lifetimes removed): +struct U { + b: Rc U>, +} +#[derive(Copy, Clone)] +struct Foo4 {} +impl Foo4 { + fn fn1(self) -> U { + U { b: Rc::new(move || self.fn1()) } + } + fn fn5(self) -> (U, U) { + let p = Rc::new(move || self.fn1()); + let p2 = p.clone(); + (U { b: p }, U { b: p2 }) + } +} + +// I can get rid of Copy/Clone if I use FnOnce: +struct V { + b: Rc V>, +} +struct Foo5 {} +impl Foo5 { + fn fn1(self) -> V { + V { b: Rc::new(move || self.fn1()) } + } + fn fn2(self) -> (V, V) { + let p = Rc::new(move || self.fn1()); + let p2 = p.clone(); + (V { b: p }, V { b: p2 }) + } + // and then either kind is fine: + fn fn3(self) -> V { + V { b: Rc::new(|| self.fn3()) } + } + fn fn4(self) -> (V, V) { + let p = Rc::new(|| self.fn3()); + let p2 = p.clone(); + (V { b: p }, V { b: p2 }) + // but this confuses me a bit. doesn't this then let me call + // an FnOnce... more than once? + } +} +