public static SingleInputSemanticProperties createProjectionPropertiesSingle(
            int[] fields, CompositeType<?> inType) {

        Character.isJavaIdentifierStart(1);

        SingleInputSemanticProperties ssp = new SingleInputSemanticProperties();

        int[] sourceOffsets = new int[inType.getArity()];
        sourceOffsets[0] = 0;
        for (int i = 1; i < inType.getArity(); i++) {
            sourceOffsets[i] = inType.getTypeAt(i - 1).getTotalFields() + sourceOffsets[i - 1];
        }

        int targetOffset = 0;
        for (int i = 0; i < fields.length; i++) {
            int sourceOffset = sourceOffsets[fields[i]];
            int numFieldsToCopy = inType.getTypeAt(fields[i]).getTotalFields();

            for (int j = 0; j < numFieldsToCopy; j++) {
                ssp.addForwardedField(sourceOffset + j, targetOffset + j);
            }
            targetOffset += numFieldsToCopy;
        }

        return ssp;
    }
@Test
    void testSingleProjectionProperties() {

        int[] pMap = new int[] {3, 0, 4};
        SingleInputSemanticProperties sp =
                SemanticPropUtil.createProjectionPropertiesSingle(
                        pMap, (CompositeType<?>) fiveIntTupleType);
        assertThat(sp.getForwardingTargetFields(0, 0)).contains(1);
        assertThat(sp.getForwardingTargetFields(0, 3)).contains(0);
        assertThat(sp.getForwardingTargetFields(0, 4)).contains(2);

        pMap = new int[] {2, 2, 1, 1};
        sp =
                SemanticPropUtil.createProjectionPropertiesSingle(
                        pMap, (CompositeType<?>) fiveIntTupleType);
        assertThat(sp.getForwardingTargetFields(0, 1)).containsExactly(2, 3);
        assertThat(sp.getForwardingTargetFields(0, 2)).containsExactly(0, 1);

        pMap = new int[] {2, 0};
        sp =
                SemanticPropUtil.createProjectionPropertiesSingle(
                        pMap, (CompositeType<?>) nestedTupleType);
        assertThat(sp.getForwardingTargetFields(0, 4)).contains(0);
        assertThat(sp.getForwardingTargetFields(0, 0)).contains(1);
        assertThat(sp.getForwardingTargetFields(0, 1)).contains(2);
        assertThat(sp.getForwardingTargetFields(0, 2)).contains(3);

        pMap = new int[] {2, 0, 1};
        sp =
                SemanticPropUtil.createProjectionPropertiesSingle(
                        pMap, (CompositeType<?>) deepNestedTupleType);
        assertThat(sp.getForwardingTargetFields(0, 6)).contains(0);
        assertThat(sp.getForwardingTargetFields(0, 0)).contains(1);
        assertThat(sp.getForwardingTargetFields(0, 1)).contains(2);
        assertThat(sp.getForwardingTargetFields(0, 2)).contains(3);
        assertThat(sp.getForwardingTargetFields(0, 3)).contains(4);
        assertThat(sp.getForwardingTargetFields(0, 4)).contains(5);
        assertThat(sp.getForwardingTargetFields(0, 5)).contains(6);

        pMap = new int[] {2, 1};
        sp =
                SemanticPropUtil.createProjectionPropertiesSingle(
                        pMap, (CompositeType<?>) pojoInTupleType);
        assertThat(sp.getForwardingTargetFields(0, 2)).contains(0);
        assertThat(sp.getForwardingTargetFields(0, 3)).contains(1);
        assertThat(sp.getForwardingTargetFields(0, 4)).contains(2);
        assertThat(sp.getForwardingTargetFields(0, 5)).contains(3);
        assertThat(sp.getForwardingTargetFields(0, 1)).contains(4);
    }