You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: patches.rs
    path of file: ./repos/tract/core/src/ops/cnn
    
    the code of the file until where you have to start completion: use crate::internal::*;
use crate::ops::cnn::PaddingSpec;
use crate::ops::nn::{DataFormat, DataShape};
use ndarray::prelude::*;

use super::PatchAxis;

use std::fmt::Debug;
use std::ops::Range;

use tract_itertools::{izip, Itertools};

#[derive(Clone, PartialEq, Eq, Hash)]
pub struct PatchSpec {
    pub input_shape: TVec<usize>,
    pub input_inner_stride: usize,
    pub output_inner_stride: usize,
    pub kernel_shape: TVec<usize>,
    pub strides: TVec<usize>,
    pub dilations: TVec<usize>,
    pub padding: PaddingSpec,
}

impl Debug for PatchSpec {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "input: {} kernel: {} strides: {} dil: {} pad: {:?}",
            self.input_shape.iter().join(","),
            self.kernel_shape.iter().join(","),
            self.strides.iter().join(","),
            self.dilations.iter().join(","),
            self.padding
        )
    }
}

impl PatchSpec {
    pub fn for_full_shape(
    
        fn reference_sumpool(&self) -> Tensor {
            let input_shape = self.input_shape();
            let output_shape = self.output_shape();
            let mut output = Tensor::zero::<f32>(&output_shape.shape).unwrap();
            for geo_out in tract_ndarray::indices(output_shape.hw_dims()) {
                for geo_ker in tract_ndarray::indices(&*self.patch.spec.kernel_shape) {
                    let geo_in: TVec<isize> = izip!(
                        geo_out.slice(),
                        geo_ker.slice(),
                        &self.patch.spec.strides,
                        &self.patch.spec.dilations,
                        &self.patch.pad_before
                    )
                    .map(|(o, k, s, d, p)| (o * s + k * d) as isize - *p as isize)
                    .collect();
                    if izip!(&geo_in, input_shape.hw_dims())
                        .any(|(g, i)| *g >= *i as isize || *g < 0)
                    {
                        continue;
                    }
                    let geo_in: TVec<usize> = geo_in.into_iter().map(|x| x as usize).collect();
                    for c in 0..*output_shape.c() {
                        let ocoords = self.data_format.from_n_c_hw(0, c, geo_out.slice()).unwrap();
                        let icoords = self.data_format.from_n_c_hw(0, c, &geo_in).unwrap();
                        output.to_array_view_mut::<f32>().unwrap()[&*ocoords.shape] +=
                            self.input.to_array_view::<f32>().unwrap()[&*icoords.shape];
                    }
                }
            }
            output
        }