partial-borrow 1.0.1

Partially borrow a struct
Documentation
// Copyright 2021 Ian Jackson and contributors
// SPDX-License-Identifier: GPL-3.0-or-later
// There is NO WARRANTY.

use super::*;
use crate::*;

#[derive(Debug,PartialBorrow)]
#[partial_borrow(Debug)]
struct AB {
  a: usize,
  b: String,
}
impl Default for AB {
  fn default() -> Self { Self { a: 42, b: "hello".into() } }
}
impl AB {
  fn bump(&mut self) {
    self.a += 1;
    self.b.push('|');
    println!("-----\n{:?}", self);
  }
  fn use_const(&self) {
    println!("{:?}", self);
  }
}
#[ext]
impl partial!(AB mut a, !*) {
  fn use_mut_a(&mut self) { *self.a += 10; }
}
#[ext]
impl partial!(AB const a, !*) {
  fn use_const_a(&self) { println!("{}", &*self.a); }
}
#[ext]
impl partial!(AB mut b, !*) {
  fn use_mut_b(&mut self) { self.b.push('U'); }
}
#[ext]
impl partial!(AB const b, !*) {
  fn use_const_b(&self) { println!("{}", &*self.b); }
}

macro_rules! test_downgrade { {
  $tfn:ident, $downgrade:path, $downgrade_mut:path
} => {
  #[test]
  fn $tfn() {
    println!("downgrade {}", stringify!($tfn));
    let mut ab = AB::default();

    // &mut Mut
    let a: &mut partial!(AB mut a) = $downgrade_mut(&mut ab);
    *a.a += 1;
    a.as_mut().use_mut_a();
    println!("{:?}", a);

    let a: &partial!(AB) = $downgrade(&ab);

    let a_ab = &**a;
    println!("{:?}", a_ab);
    a.use_const();
    a_ab.use_const();

    ab.bump();

    // &mut Const
    let a: &mut partial!(AB const a, !*) = $downgrade_mut(&mut ab);
    println!("{}", &*a.a);
    a.use_const_a();
    println!("{:?}", a);

    // &Mut, &Const
    let a0: &partial!(AB mut a, !*) = $downgrade(&ab);
    let a1: &partial!(AB const a, !*) = $downgrade(&ab);
    println!("{} {}", &*a0.a, &*a1.a);
    a0.as_ref().use_const_a();
    a1.use_const_a();
    println!("{:?} {:?}", a0, a1);

    ab.bump();
  }
}}

test_downgrade!{ downgrade, Downgrade::downgrade, Downgrade::downgrade_mut }
test_downgrade!{ asref,     AsRef::as_ref,        AsMut::as_mut            }

macro_rules! test_split { {
  $tfn:ident, $split:path, $split_mut:path
} => {
  #[test]
  fn $tfn() {
    println!("split {}", stringify!($tfn));
    let mut ab = AB::default();

    // &mut Mut
    let (a,b): (&mut partial!(AB mut a, !*),
                &mut partial!(AB mut b, !*)) = $split_mut(&mut ab);
    *a.a += 1;   
    *b.b += "+"; 
    a.use_mut_a();
    b.use_mut_b();
    println!("{:?} {:?}", a, b);

    ab.bump();

    // &mut Const
    let (a,b): (&mut partial!(AB const a, !*),
                &mut partial!(AB const a, mut *)) = $split_mut(&mut ab);
    println!("{}", &*a.a);
    *b.b += "#"; 
    a.use_const_a();
    b.as_mut().use_mut_b();
    println!("{:?} {:?}", a, b);

    // &mut Const Const
    let (a,b): (&mut partial!(AB),
                &mut partial!(AB)) = $split_mut(&mut ab);
    println!("{} {}", &*a.a, &*b.b);
    a.as_ref().use_const_a();
    b.as_ref().use_const_b();
    let a_ab = &**a;
    let b_ab = &**b;
    println!("{:?} {:?} {:?} {:?}", a, b, a_ab, b_ab);
    a.use_const();
    b.use_const();
    a_ab.use_const();
    b_ab.use_const();

    ab.bump();

    // &Mut
    let (a,b): (&partial!(AB mut a, !*),
                &partial!(AB mut b, !*)) = $split(&ab);
    println!("{} {}", &*a.a, &*b.b);
    a.as_ref().use_const_a();
    b.as_ref().use_const_b();
    println!("{:?} {:?}", a, b);

    ab.bump();

    // &Const
    let (a,b): (&partial!(AB const a, !*),
                &partial!(AB const a, mut *)) = $split(&ab);
    println!("{} {}", &*a.a, &*b.b);
    a.use_const_a();
    b.as_ref().use_const_b();
    println!("{:?} {:?}", a, b);

    ab.bump();
  }
}}

test_split!{ split_off,  SplitOff::split_off,   SplitOff::split_off_mut   }
test_split!{ split_into, SplitInto::split_into, SplitInto::split_into_mut }
test_split!{ split_into_into, Into::into,       Into::into                }
test_split!{ split_from_from, From::from,       From::from                }